diff --git a/CMakeLists.txt b/CMakeLists.txt index 33ecfa4f649b57a23b0b5a4423a08331b3a88244..f363cbb10fa2bdcbce618f0f0e04972eff4a8adc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ set(GNU_CXX_MIN_VERSION "7.0.0") set(CLANG_CXX_MIN_VERSION "5.0.0") # Pugs default compiler flags -set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} -Wall -Wextra") +set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} -Wall -Wextra -pedantic") if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "${GNU_CXX_MIN_VERSION}") @@ -153,11 +153,11 @@ set(PUGS_HAS_MPI ${MPI_FOUND}) find_program(CLANG_FORMAT clang-format) if (CLANG_FORMAT) add_custom_target(clang-format - COMMAND echo "running ${CLANG_FORMAT} ..." COMMAND ${CMAKE_COMMAND} -DPUGS_SOURCE_DIR="${PUGS_SOURCE_DIR}" -DCLANG_FORMAT="${CLANG_FORMAT}" - -P ${PUGS_SOURCE_DIR}/cmake/ClangFormatProcess.cmake) + -P ${PUGS_SOURCE_DIR}/cmake/ClangFormatProcess.cmake + COMMENT "running ${CLANG_FORMAT} ...") else () message(WARNING "clang-format no found!") endif() @@ -273,7 +273,7 @@ include_directories(${PUGS_SOURCE_DIR}/packages/rang/include) include_directories(${PUGS_SOURCE_DIR}/packages/CLI11/include) # PEGTL -include_directories(${PUGS_SOURCE_DIR}/packages/PEGTL/include/tao) +include_directories(SYSTEM ${PUGS_SOURCE_DIR}/packages/PEGTL/include/tao) # Pugs src add_subdirectory(${PUGS_SOURCE_DIR}/src) @@ -289,7 +289,7 @@ add_subdirectory(tests) enable_testing() add_custom_target(run_unit_tests - COMMAND ${CMAKE_CTEST_COMMAND} -j ${PROCESSOR_COUNT} + COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unit_tests mpi_unit_tests COMMENT "Executing unit tests." ) @@ -342,13 +342,15 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") add_custom_target(coverage ALL # in coverage mode we do coverage! + # zero all counters + COMMAND ${FASTCOV} -q -z + # Run tests - COMMAND ${CMAKE_CTEST_COMMAND} -j ${PROCESSOR_COUNT} + COMMAND ${CMAKE_CTEST_COMMAND} COMMAND ${FASTCOV} -q --gcov "${GCOV_BIN}" --include "${PUGS_SOURCE_DIR}/src" - --exclude "${PUGS_SOURCE_DIR}/src/main.cpp" - --exclude "${PUGS_SOURCE_DIR}/src/utils/BacktraceManager.*" + --exclude "${PUGS_SOURCE_DIR}/src/main.cpp" "${PUGS_SOURCE_DIR}/src/utils/BacktraceManager.*" --lcov -o coverage.info -n COMMAND ${LCOV} --gcov "${GCOV_BIN}" --list coverage.info @@ -363,14 +365,14 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") add_custom_target(coverage ALL # in coverage mode we do coverage! # Cleanup previously generated profiling data - COMMAND ${LCOV} -q --gcov "${GCOV_BIN}" --base-directory "${PUGS_SOURCE_DIR}/src" --directory "${PUGS_BINARY_DIR}" --zerocounters + COMMAND ${LCOV} -q --gcov "${GCOV_BIN}" --base-directory "${PUGS_BINARY_DIR}/src" --directory "${PUGS_BINARY_DIR}" --zerocounters # Initialize profiling data with zero coverage for every instrumented line of the project # This way the percentage of total lines covered will always be correct, even when not all source code files were loaded during the test(s) - COMMAND ${LCOV} -q --gcov "${GCOV_BIN}" --base-directory "${PUGS_SOURCE_DIR}/src" --directory "${PUGS_BINARY_DIR}" --capture --initial --output-file coverage_base.info + COMMAND ${LCOV} -q --gcov "${GCOV_BIN}" --base-directory "${PUGS_BINARY_DIR}/src" --directory "${PUGS_BINARY_DIR}" --capture --initial --output-file coverage_base.info # Run tests - COMMAND ${CMAKE_CTEST_COMMAND} -j ${PROCESSOR_COUNT} + COMMAND ${CMAKE_CTEST_COMMAND} # Collect data from executions - COMMAND ${LCOV} --gcov "${GCOV_BIN}" --base-directory "${PUGS_SOURCE_DIR}/src" --directory "${PUGS_BINARY_DIR}" --capture --output-file coverage_ctest.info + COMMAND ${LCOV} --gcov "${GCOV_BIN}" --base-directory "${PUGS_BINARY_DIR}/src" --directory "${PUGS_BINARY_DIR}" --capture --output-file coverage_ctest.info # Combine base and ctest results COMMAND ${LCOV} --gcov "${GCOV_BIN}" -q --add-tracefile coverage_base.info --add-tracefile coverage_ctest.info --output-file coverage_full.info # Extract only project data (--no-capture or --remove options may be used to select collected data) @@ -389,7 +391,6 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") ) endif() - find_program(GENHTML genhtml) if(NOT GENHTML) message(WARNING "genhtml not found, cannot perform report-coverage.") @@ -398,7 +399,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") ALL COMMAND ${CMAKE_COMMAND} -E remove_directory "${PUGS_BINARY_DIR}/coverage" COMMAND ${CMAKE_COMMAND} -E make_directory "${PUGS_BINARY_DIR}/coverage" - COMMAND ${GENHTML} -q -o coverage -t "${CMAKE_PROJECT_NAME} test coverage" --ignore-errors source --legend --num-spaces 4 coverage.info + COMMAND ${GENHTML} --demangle-cpp -q -o coverage -t "${CMAKE_PROJECT_NAME} test coverage" --ignore-errors source --legend --num-spaces 2 coverage.info DEPENDS coverage COMMENT "Building coverage html report." WORKING_DIRECTORY "${PUGS_BINARY_DIR}" @@ -422,6 +423,10 @@ target_link_libraries( PugsMesh PugsUtils PugsLanguage + PugsLanguageAST + PugsLanguageModules + PugsMesh + PugsLanguageUtils kokkos ${PARMETIS_LIBRARIES} ${MPI_CXX_LINK_FLAGS} ${MPI_CXX_LIBRARIES} diff --git a/cmake/CoverageRemoveObsoleteFiles.cmake b/cmake/CoverageRemoveObsoleteFiles.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d388916a71d81ba1e4a5651bbfd736d997bd2fbe --- /dev/null +++ b/cmake/CoverageRemoveObsoleteFiles.cmake @@ -0,0 +1,9 @@ +# ------------------------------------------------------------------------------ +# Remove obsolete generated files that could last after a failing test-suite run +# These are generally trailing .gcda files +# ------------------------------------------------------------------------------ + +file(GLOB_RECURSE GCDA_FILE_LIST "${PUGS_BINARY_DIR}/*.gcda") +if(GCDA_FILE_LIST) + file(REMOVE ${GCDA_FILE_LIST}) +endif() diff --git a/packages/PEGTL/.appveyor.yml b/packages/PEGTL/.appveyor.yml index 8150fbf6e507bbb55488376dd88bdc72add322fc..716434a3043a74f22d63bcb374dac3b7a9c7766d 100644 --- a/packages/PEGTL/.appveyor.yml +++ b/packages/PEGTL/.appveyor.yml @@ -1,11 +1,7 @@ version: '{branch}-{build}' os: -- Visual Studio 2017 - -configuration: -- Release -- Debug + - Visual Studio 2017 skip_commits: files: @@ -14,21 +10,58 @@ skip_commits: environment: matrix: - GENERATOR: Visual Studio 15 2017 + platform: x86 + configuration: Debug - - GENERATOR: Visual Studio 15 2017 Win64 + - GENERATOR: Visual Studio 15 2017 + platform: x86 + configuration: Release - GENERATOR: Visual Studio 15 2017 - CONAN_VISUAL_VERSIONS: 15 - PYTHON: "C:\\Python27" - PYTHON_VERSION: "2.7.8" - PYTHON_ARCH: "32" - CONAN: TRUE + platform: x64 + configuration: Debug -init: [] + - GENERATOR: Visual Studio 15 2017 + platform: x64 + configuration: Release -install: -- if defined CONAN (pip.exe install -U conan conan-package-tools) -- if defined CONAN (conan profile new default --detect) + - GENERATOR: Visual Studio 15 2017 Win64 + platform: x86 + configuration: Debug + + - GENERATOR: Visual Studio 15 2017 Win64 + platform: x86 + configuration: Release + + - GENERATOR: Visual Studio 15 2017 Win64 + platform: x64 + configuration: Debug + + - GENERATOR: Visual Studio 15 2017 Win64 + platform: x64 + configuration: Release + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + GENERATOR: Visual Studio 16 2019 + platform: x86 + configuration: Debug + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + GENERATOR: Visual Studio 16 2019 + platform: x86 + configuration: Release + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + GENERATOR: Visual Studio 16 2019 + platform: x64 + configuration: Debug + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + GENERATOR: Visual Studio 16 2019 + platform: x64 + configuration: Release + +init: [] before_build: - if defined BINDIR (set "PATH=%BINDIR%;%PATH:C:\Program Files\Git\usr\bin;=%") @@ -41,5 +74,4 @@ build_script: test_script: - ctest -C "%CONFIGURATION%" --output-on-failure -- if defined CONAN (cd ..) -- if defined CONAN (python .conan/build.py) + diff --git a/packages/PEGTL/.clang-tidy b/packages/PEGTL/.clang-tidy new file mode 100644 index 0000000000000000000000000000000000000000..14eb1216c414dfe3269d2b3195855173b18299f1 --- /dev/null +++ b/packages/PEGTL/.clang-tidy @@ -0,0 +1,32 @@ +Checks: >- + bugprone-*, + cppcoreguidelines-slicing, + cppcoreguidelines-special-member-functions, + google-build-explicit-make-pair, + google-build-namespaces, + google-default-arguments, + google-global-names-in-headers, + google-readability-casting, + llvm-*, + -llvm-namespace-comment, + misc-*, + -misc-non-private-member-variables-in-classes, + -misc-unused-alias-decls, + modernize-*, + -modernize-avoid-c-arrays, + -modernize-concat-nested-namespaces, + -modernize-raw-string-literal, + -modernize-use-trailing-return-type, + performance-*, + readability-*, + -readability-avoid-const-params-in-decls, + -readability-magic-numbers, + +CheckOptions: + - { key: readability-identifier-naming.ClassCase, value: lower_case } + - { key: readability-identifier-naming.FunctionCase, value: lower_case } + - { key: readability-identifier-naming.ParameterCase, value: lower_case } + - { key: readability-identifier-naming.StructCase, value: aNy_CasE } # PEGTL rules + - { key: readability-identifier-naming.VariableCase, value: lower_case } + +WarningsAsErrors: '*' diff --git a/packages/PEGTL/.conan/build.py b/packages/PEGTL/.conan/build.py deleted file mode 100644 index 838e7975543621810e255aa80c7d5a61331ea578..0000000000000000000000000000000000000000 --- a/packages/PEGTL/.conan/build.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import os -import re -from cpt.packager import ConanMultiPackager -from cpt.ci_manager import CIManager -from cpt.printer import Printer - - -class BuilderSettings(object): - @property - def username(self): - """ Set taocpp as package's owner - """ - return os.getenv("CONAN_USERNAME", "taocpp") - - @property - def upload(self): - """ Set taocpp repository to be used on upload. - The upload server address could be customized by env var - CONAN_UPLOAD. If not defined, the method will check the branch name. - Only master or CONAN_STABLE_BRANCH_PATTERN will be accepted. - The master branch will be pushed to testing channel, because it does - not match the stable pattern. Otherwise it will upload to stable - channel. - """ - if os.getenv("CONAN_UPLOAD", None) is not None: - return os.getenv("CONAN_UPLOAD") - - printer = Printer(None) - ci_manager = CIManager(printer) - branch = ci_manager.get_branch() - - patterns = [r"v?\d+\.\d+\.\d+-.*", self.stable_branch_pattern] - for pattern in patterns: - prog = re.compile(pattern) - if branch and prog.match(branch): - return "https://api.bintray.com/conan/taocpp/public-conan" - - @property - def upload_only_when_stable(self): - """ Force to upload when running over tag branch - """ - return os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True) - - @property - def stable_branch_pattern(self): - """ Only upload the package the branch name is like a tag - """ - return os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"\d+\.\d+\.\d+") - - @property - def reference(self): - """ Read project version from CMake file to create Conan referece - """ - pattern = re.compile(r"project\(pegtl VERSION (\d+\.\d+\.\d+) LANGUAGES CXX\)") - version = None - with open('CMakeLists.txt') as file: - for line in file: - result = pattern.match(line) - if result: - version = result.group(1) - if not version: - raise Exception("Could not find version in CMakeLists.txt") - return os.getenv("CONAN_REFERENCE", "pegtl/{}@taocpp/stable".format(version)) - -if __name__ == "__main__": - settings = BuilderSettings() - builder = ConanMultiPackager( - reference=settings.reference, - username=settings.username, - upload=settings.upload, - upload_only_when_stable=settings.upload_only_when_stable, - stable_branch_pattern=settings.stable_branch_pattern, - test_folder=os.path.join(".conan", "test_package")) - builder.add() - builder.run() diff --git a/packages/PEGTL/.conan/test_package/CMakeLists.txt b/packages/PEGTL/.conan/test_package/CMakeLists.txt deleted file mode 100644 index 33bc5e0f830aeb3734ed72fb5193122762bdcd1b..0000000000000000000000000000000000000000 --- a/packages/PEGTL/.conan/test_package/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -project(test_package CXX) -cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR) - -set(CMAKE_VERBOSE_MAKEFILE TRUE) - -include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) -conan_basic_setup() - -find_package(PEGTL REQUIRED CONFIG) - -add_executable(${PROJECT_NAME} test_package.cpp) -target_link_libraries(${PROJECT_NAME} taocpp::pegtl) diff --git a/packages/PEGTL/.conan/test_package/conanfile.py b/packages/PEGTL/.conan/test_package/conanfile.py deleted file mode 100644 index fc54c64a69fc0741aaf61ad6c3c62e08ffdbaf4c..0000000000000000000000000000000000000000 --- a/packages/PEGTL/.conan/test_package/conanfile.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/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): - with tools.environment_append(RunEnvironment(self).vars): - bin_path = os.path.join("bin", "test_package") - self.run('{} "2 + 3 * -7" "(2 + 3) * 7"'.format(bin_path)) diff --git a/packages/PEGTL/.conan/test_package/test_package.cpp b/packages/PEGTL/.conan/test_package/test_package.cpp deleted file mode 100644 index f16aa23099613b2ab809209ad0c7f32f2f0cf8f2..0000000000000000000000000000000000000000 --- a/packages/PEGTL/.conan/test_package/test_package.cpp +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#include <cassert> -#include <functional> -#include <iostream> -#include <map> -#include <sstream> -#include <vector> - -#include <tao/pegtl.hpp> - -// Include the analyze function that checks -// a grammar for possible infinite cycles. - -#include <tao/pegtl/analyze.hpp> - -namespace pegtl = TAO_PEGTL_NAMESPACE; - -namespace calculator -{ - // This enum is used for the order in which the operators are - // evaluated, i.e. the priority of the operators; a higher - // number indicates a lower priority. - - enum class order : int - { - }; - - // For each binary operator known to the calculator we need an - // instance of the following data structure with the priority, - // and a function that performs the calculation. All operators - // are left-associative. - - struct op - { - order p; - std::function< long( long, long ) > f; - }; - - // Class that takes care of an operand and an operator stack for - // shift-reduce style handling of operator priority; in a - // reduce-step it calls on the functions contained in the op - // instances to perform the calculation. - - struct stack - { - void push( const op& b ) - { - while( ( !m_o.empty() ) && ( m_o.back().p <= b.p ) ) { - reduce(); - } - m_o.push_back( b ); - } - - void push( const long l ) - { - m_l.push_back( l ); - } - - long finish() - { - while( !m_o.empty() ) { - reduce(); - } - assert( m_l.size() == 1 ); - const auto r = m_l.back(); - m_l.clear(); - return r; - } - - private: - std::vector< op > m_o; - std::vector< long > m_l; - - void reduce() - { - assert( !m_o.empty() ); - assert( m_l.size() > 1 ); - - const auto r = m_l.back(); - m_l.pop_back(); - const auto l = m_l.back(); - m_l.pop_back(); - const auto o = m_o.back(); - m_o.pop_back(); - m_l.push_back( o.f( l, r ) ); - } - }; - - // Additional layer, a "stack of stacks", to clearly show how bracketed - // sub-expressions can be easily processed by giving them a stack of - // their own. Once a bracketed sub-expression has finished evaluation on - // its stack, the result is pushed onto the next higher stack, and the - // sub-expression's temporary stack is discarded. The top-level calculation - // is handled just like a bracketed sub-expression, on the first stack pushed - // by the constructor. - - struct stacks - { - stacks() - { - open(); - } - - void open() - { - m_v.emplace_back(); - } - - template< typename T > - void push( const T& t ) - { - assert( !m_v.empty() ); - m_v.back().push( t ); - } - - void close() - { - assert( m_v.size() > 1 ); - const auto r = m_v.back().finish(); - m_v.pop_back(); - m_v.back().push( r ); - } - - long finish() - { - assert( m_v.size() == 1 ); - return m_v.back().finish(); - } - - private: - std::vector< stack > m_v; - }; - - // A wrapper around the data structures that contain the binary - // operators for the calculator. - - struct operators - { - operators() - { - // By default we initialise with all binary operators from the C language that can be - // used on integers, all with their usual priority. - - insert( "*", order( 5 ), []( const long l, const long r ) { return l * r; } ); - insert( "/", order( 5 ), []( const long l, const long r ) { return l / r; } ); - insert( "%", order( 5 ), []( const long l, const long r ) { return l % r; } ); - insert( "+", order( 6 ), []( const long l, const long r ) { return l + r; } ); - insert( "-", order( 6 ), []( const long l, const long r ) { return l - r; } ); - insert( "<<", order( 7 ), []( const long l, const long r ) { return l << r; } ); - insert( ">>", order( 7 ), []( const long l, const long r ) { return l >> r; } ); - insert( "<", order( 8 ), []( const long l, const long r ) { return l < r; } ); - insert( ">", order( 8 ), []( const long l, const long r ) { return l > r; } ); - insert( "<=", order( 8 ), []( const long l, const long r ) { return l <= r; } ); - insert( ">=", order( 8 ), []( const long l, const long r ) { return l >= r; } ); - insert( "==", order( 9 ), []( const long l, const long r ) { return l == r; } ); - insert( "!=", order( 9 ), []( const long l, const long r ) { return l != r; } ); - insert( "&", order( 10 ), []( const long l, const long r ) { return l & r; } ); - insert( "^", order( 11 ), []( const long l, const long r ) { return l ^ r; } ); - insert( "|", order( 12 ), []( const long l, const long r ) { return l | r; } ); - insert( "&&", order( 13 ), []( const long l, const long r ) { return ( ( l != 0 ) && ( r != 0 ) ) ? 1 : 0; } ); - insert( "||", order( 14 ), []( const long l, const long r ) { return ( ( l != 0 ) || ( r != 0 ) ) ? 1 : 0; } ); - } - - // Arbitrary user-defined operators can be added at runtime. - - void insert( const std::string& name, const order p, const std::function< long( long, long ) >& f ) - { - assert( !name.empty() ); - m_ops.emplace( name, op{ p, f } ); - } - - const std::map< std::string, op >& ops() const - { - return m_ops; - } - - private: - std::map< std::string, op > m_ops; - }; - - // Here the actual grammar starts. - - using namespace pegtl; // NOLINT - - // Comments are introduced by a '#' and proceed to the end-of-line/file. - - struct comment - : if_must< one< '#' >, until< eolf > > - {}; - - // The calculator ignores all spaces and comments; space is a pegtl rule - // that matches the usual ascii characters ' ', '\t', '\n' etc. In other - // words, everything that is space or a comment is ignored. - - struct ignored - : sor< space, comment > - {}; - - // Since the binary operators are taken from a runtime data structure - // (rather than hard-coding them into the grammar), we need a custom - // rule that attempts to match the input against the current map of - // operators. - - struct infix - { - using analyze_t = analysis::generic< analysis::rule_type::any >; - - template< apply_mode, - rewind_mode, - template< typename... > - class Action, - template< typename... > - class Control, - typename Input, - typename... States > - static bool match( Input& in, const operators& b, stacks& s, States&&... /*unused*/ ) - { - // Look for the longest match of the input against the operators in the operator map. - - return match( in, b, s, std::string() ); - } - - private: - template< typename Input > - static bool match( Input& in, const operators& b, stacks& s, std::string t ) - { - if( in.size( t.size() + 1 ) > t.size() ) { - t += in.peek_char( t.size() ); - const auto i = b.ops().lower_bound( t ); - if( i != b.ops().end() ) { - if( match( in, b, s, t ) ) { - return true; - } - if( i->first == t ) { - // While we are at it, this rule also performs the task of what would - // usually be an associated action: To push the matched operator onto - // the operator stack. - s.push( i->second ); - in.bump( t.size() ); - return true; - } - } - } - return false; - } - }; - - // A number is a non-empty sequence of digits preceeded by an optional sign. - - struct number - : seq< opt< one< '+', '-' > >, plus< digit > > - {}; - - struct expression; - - // A bracketed expression is introduced by a '(' and, in this grammar, must - // proceed with an expression and a ')'. - - struct bracket - : if_must< one< '(' >, expression, one< ')' > > - {}; - - // An atomic expression, i.e. one without operators, is either a number or - // a bracketed expression. - - struct atomic - : sor< number, bracket > - {}; - - // An expression is a non-empty list of atomic expressions where each pair - // of atomic expressions is separated by an infix operator and we allow - // the rule ignored as padding (before and after every singlar expression). - - struct expression - : list< atomic, infix, ignored > - {}; - - // The top-level grammar allows one expression and then expects eof. - - struct grammar - : must< expression, eof > - {}; - - // After the grammar we proceed with the additional actions that are - // required to let our calculator actually do something. - - template< typename Rule > - struct action - {}; - - // This action will be called when the number rule matches; it converts the - // matched portion of the input to a long and pushes it onto the operand - // stack. - - template<> - struct action< number > - { - template< typename Input > - static void apply( const Input& in, const operators& /*unused*/, stacks& s ) - { - std::stringstream ss( in.string() ); - long v; - ss >> v; - s.push( v ); - } - }; - - // The actions for the brackets call functions that create, and collect - // a temporary additional stack for evaluating the bracketed expression. - - template<> - struct action< one< '(' > > - { - static void apply0( const operators& /*unused*/, stacks& s ) - { - s.open(); - } - }; - - template<> - struct action< one< ')' > > - { - static void apply0( const operators& /*unused*/, stacks& s ) - { - s.close(); - } - }; - -} // namespace calculator - -int main( int argc, char** argv ) -{ - // Check the grammar for some possible issues. - - pegtl::analyze< calculator::grammar >(); - - // The objects required as state by the actions. - - calculator::stacks s; - calculator::operators b; - - for( int i = 1; i < argc; ++i ) { - // Parse and process the command-line arguments as calculator expressions... - - pegtl::argv_input in( argv, i ); - pegtl::parse< calculator::grammar, calculator::action >( in, b, s ); - - // ...and print the respective results to std::cout. - - std::cout << s.finish() << std::endl; - } - return 0; -} diff --git a/packages/PEGTL/.gitignore b/packages/PEGTL/.gitignore index 454bccb45403f97193099b1a478996608a632508..90173b58d947cdff1175a16b8c2a9e67ec4ca0bf 100644 --- a/packages/PEGTL/.gitignore +++ b/packages/PEGTL/.gitignore @@ -1,3 +1,4 @@ *~ build private +/.vs diff --git a/packages/PEGTL/.gitrepo b/packages/PEGTL/.gitrepo index 943a8805864d887b81d04ed035cee2e1181d3661..7eea19117c858927ae7c942b0fe1631d3c411044 100644 --- a/packages/PEGTL/.gitrepo +++ b/packages/PEGTL/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = git@github.com:taocpp/PEGTL.git branch = master - commit = 68790bd2c25fceff1049e9fc2fb9528ca4d93bbf - parent = 0fc26ddb5da553e9b9ddff3db48b3d6a1617eb96 - cmdver = 0.4.0 + commit = 1a4a2d0df43f773893e0e4102d56d85e6b3fb7fc + parent = 28dff7b443629a23205fd32909491e7e5de495a3 + cmdver = 0.4.1 method = merge diff --git a/packages/PEGTL/.travis.yml b/packages/PEGTL/.travis.yml index 32500f24224920c429068cea59853f9db37b5f0e..95e20d5032f8e6f5e3cd3adb8f7d200153d039a8 100644 --- a/packages/PEGTL/.travis.yml +++ b/packages/PEGTL/.travis.yml @@ -2,151 +2,208 @@ language: generic os: linux dist: xenial -matrix: +jobs: include: - - compiler: gcc + - &gcc-7 + compiler: gcc addons: apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7'] + sources: [ ubuntu-toolchain-r-test ] + packages: [ g++-7 ] env: - CXX=g++-7 - - compiler: gcc + - &gcc-8 + compiler: gcc addons: apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-8'] + sources: [ ubuntu-toolchain-r-test ] + packages: [ g++-8 ] env: - CXX=g++-8 + - <<: *gcc-8 + env: + - CXX=g++-8 + - CPPFLAGS="-fno-rtti" + + - &gcc-9 + compiler: gcc + addons: + apt: + sources: [ ubuntu-toolchain-r-test ] + packages: [ g++-9 ] + env: + - CXX=g++-9 + - compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-5'] - packages: ['clang-5.0', 'g++-7'] + sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-5 ] + packages: [ clang-5.0, g++-7 ] env: - CXX=clang++-5.0 - compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-6'] - packages: ['clang-6.0', 'g++-7'] + sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-6 ] + packages: [ clang-6.0, g++-7 ] env: - CXX=clang++-6.0 - compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-7'] - packages: ['clang-7', 'g++-7'] + sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-7 ] + packages: [ clang-7, g++-7 ] env: - CXX=clang++-7 - compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-8'] - packages: ['clang-8', 'g++-8'] + sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-8 ] + packages: [ clang-8, g++-8 ] env: - CXX=clang++-8 - compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-8'] - packages: ['clang-8', 'g++-8'] + sources: &clang-9-sources + - ubuntu-toolchain-r-test + - sourceline: deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main + key_url: https://apt.llvm.org/llvm-snapshot.gpg.key + packages: [ clang-9, g++-9 ] env: - - CXX=clang++-8 - - CPPFLAGS=-fms-extensions + - CXX=clang++-9 - - os: osx - osx_image: xcode9.4 + - &clang-10 compiler: clang + addons: + apt: + sources: &clang-10-sources + - ubuntu-toolchain-r-test + - sourceline: deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main + key_url: https://apt.llvm.org/llvm-snapshot.gpg.key + packages: [ clang-10, g++-9 ] env: - - CXX=clang++ + - CXX=clang++-10 - - os: osx - osx_image: xcode10.2 + - <<: *clang-10 + env: + - CXX=clang++-10 + - CPPFLAGS="-fms-extensions" + + - <<: *clang-10 + env: + - CXX=clang++-10 + - CPPFLAGS="-fno-rtti" + + - &osx + os: osx + osx_image: xcode9.4 compiler: clang env: - CXX=clang++ - - compiler: gcc + - <<: *osx + osx_image: xcode10.3 + + - <<: *osx + osx_image: xcode11.4 + + - &android + compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-8'] + packages: + - openjdk-8-jdk + before_install: + - export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 + - wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip + - unzip -qq sdk-tools-linux-4333796.zip -d /opt/android-sdk + - rm sdk-tools-linux-4333796.zip + - echo "y" | /opt/android-sdk/tools/bin/sdkmanager "platform-tools" "system-images;android-24;default;${ANDROID_ABI}" "platforms;android-24" "emulator" "ndk-bundle" "cmake;3.10.2.4988404" > /dev/null + before_script: + - export TERM=dumb + - export _NO_CHECK_SIGNATURE=true + - export ANDROID_SDK_ROOT=/opt/android-sdk + - echo no | /opt/android-sdk/tools/bin/avdmanager create avd -n test -k "system-images;android-24;default;${ANDROID_ABI}" + - /opt/android-sdk/emulator/emulator -avd test -no-audio -no-window -dns-server 8.8.8.8 & + #- android-wait-for-emulator || android-wait-for-emulator + - /opt/android-sdk/platform-tools/adb shell input keyevent 82 & + script: + # Using the ninja build command. Is much faster then make build command. + - /opt/android-sdk/cmake/3.10.2.4988404/bin/cmake -H. -Bcmake-build -GNinja -DANDROID_ABI=${ANDROID_ABI} -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=/opt/android-sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=${ANDROID_PLATFORM} -DCMAKE_MAKE_PROGRAM=/opt/android-sdk/cmake/3.10.2.4988404/bin/ninja -DPEGTL_BUILD_EXAMPLES=OFF + - /opt/android-sdk/cmake/3.10.2.4988404/bin/cmake --build cmake-build --target all + # FIXME android emulator stuck sometimes - cd cmake-build && /opt/android-sdk/cmake/3.10.2.4988404/bin/ctest --output-on-failure env: - - CXX=g++-8 + - ANDROID_ABI=armeabi-v7a + - ANDROID_PLATFORM=android-22 + + - <<: *android + env: + - ANDROID_ABI=armeabi-v7a + - ANDROID_PLATFORM=android-24 + + - <<: *android + env: + - ANDROID_ABI=arm64-v8a + - ANDROID_PLATFORM=android-24 + + - <<: *gcc-9 + env: + - CXX=g++-9 - CPPFLAGS="-fsanitize=undefined -fuse-ld=gold" - - compiler: gcc - sudo: true - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-8'] + - <<: *gcc-9 env: - - CXX=g++-8 + - CXX=g++-9 - CPPFLAGS="-fsanitize=address -fuse-ld=gold" - - compiler: clang - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-8'] - packages: ['clang-8', 'g++-8'] + - <<: *clang-10 env: - - CXX=clang++-8 - - CPPFLAGS=-fsanitize=undefined + - CXX=clang++-10 + - CPPFLAGS="-fsanitize=undefined" - - compiler: clang - sudo: true - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-8'] - packages: ['clang-8', 'g++-8'] + - <<: *clang-10 env: - - CXX=clang++-8 - - CPPFLAGS=-fsanitize=address + - CXX=clang++-10 + - CPPFLAGS="-fsanitize=address" - compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-8'] - packages: ['clang-8', 'clang-tidy-8', 'g++-8'] + sources: *clang-10-sources + packages: [ clang-10, clang-tidy-10, g++-9 ] env: - - CXX=clang++-8 - - CLANG_TIDY=clang-tidy-8 + - CXX=clang++-10 + - CLANG_TIDY=clang-tidy-10 script: - - "sed -i 's#namespace TAO_PEGTL_NAMESPACE#namespace tao::pegtl#g' $(find . -name '*.[hc]pp')" - make -kj3 clang-tidy - compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-xenial-8'] - packages: ['clang-8', 'clang-tools-8', 'g++-8'] + sources: *clang-10-sources + packages: [ clang-tools-10, g++-9 ] script: - - scan-build-8 --use-c++=clang++-8 --status-bugs make -kj3 + - scan-build-10 --use-c++=clang++-10 --status-bugs make -kj3 - compiler: gcc addons: apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-8', 'valgrind'] + sources: [ ubuntu-toolchain-r-test ] + packages: [ g++-9, valgrind ] env: - - CXX=g++-8 + - CXX=g++-9 - SPECIAL=valgrind script: - make -kj3 valgrind - - compiler: gcc - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7'] + - <<: *gcc-7 env: - CXX=g++-7 - CXXFLAGS="-O0 --coverage" @@ -156,17 +213,14 @@ matrix: - make -kj3 check - coveralls --gcov gcov-7 --gcov-options '\-lp' --exclude src - - language: python - python: - - "3.6" - sudo: required - install: - - pip install conan conan-package-tools - env: - - CONAN_GCC_VERSIONS=7 - - CONAN_DOCKER_IMAGE=lasote/conangcc7 + - compiler: clang + addons: + apt: + sources: *clang-9-sources + packages: [ clang-format-9, g++-9 ] script: - - python .conan/build.py + - clang-format-9 -i -style=file $(find . -name '[^.]*.[hc]pp') + - git diff --exit-code script: - $CXX --version diff --git a/packages/PEGTL/CMakeLists.txt b/packages/PEGTL/CMakeLists.txt index 410ec90d1380f6d0461ce48eecfedfd117b90412..0fe7e8e7a5d93ffa969b7129b84ee9b71de03270 100644 --- a/packages/PEGTL/CMakeLists.txt +++ b/packages/PEGTL/CMakeLists.txt @@ -1,6 +1,11 @@ cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) -project(pegtl VERSION 3.0.0 LANGUAGES CXX) +# Read version from version.hpp +file(READ "${CMAKE_CURRENT_LIST_DIR}/include/tao/pegtl/version.hpp" version_hpp_data) +string(REGEX MATCH "#define TAO_PEGTL_VERSION \"([^\"]+)\"" _ ${version_hpp_data}) +set(PEGTL_VERSION "${CMAKE_MATCH_1}") + +project(pegtl VERSION ${PEGTL_VERSION} LANGUAGES CXX) if(${PROJECT_NAME}_FOUND) # Multiple versions of PEGTL can't co-exist @@ -55,6 +60,13 @@ endif() # Make package findable configure_file(cmake/dummy-config.cmake.in pegtl-config.cmake @ONLY) +# Ignore pointer width differences since this is a header-only library +unset(CMAKE_SIZEOF_VOID_P) + +# Enable version checks in find_package +include(CMakePackageConfigHelpers) +write_basic_package_version_file(pegtl-config-version.cmake COMPATIBILITY SameMajorVersion) + # install and export target install(TARGETS pegtl EXPORT pegtl-targets) @@ -64,5 +76,6 @@ install(EXPORT pegtl-targets DESTINATION ${PEGTL_INSTALL_CMAKE_DIR} ) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pegtl-config-version.cmake DESTINATION ${PEGTL_INSTALL_CMAKE_DIR}) install(DIRECTORY include/ DESTINATION ${PEGTL_INSTALL_INCLUDE_DIR}) install(FILES LICENSE DESTINATION ${PEGTL_INSTALL_DOC_DIR}) diff --git a/packages/PEGTL/LICENSE b/packages/PEGTL/LICENSE index 378c177b917908b7b86e7d4a499cfed714215157..17d3ad29c2972cdcc8a5ae536d6811352cfb4a3f 100644 --- a/packages/PEGTL/LICENSE +++ b/packages/PEGTL/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2007-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2007-2020 Dr. Colin Hirsch and Daniel Frey Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/packages/PEGTL/Makefile b/packages/PEGTL/Makefile index 983c806fa07b1a5bdd1f68bf5a767f2c6d55cda6..9ff538aff11cec39c905b5d76871e6338af76b73 100644 --- a/packages/PEGTL/Makefile +++ b/packages/PEGTL/Makefile @@ -1,5 +1,5 @@ # The Art of C++ -# Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +# Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey # Please see LICENSE for license or visit https://github.com/taocpp/PEGTL .SUFFIXES: @@ -39,7 +39,7 @@ SOURCES := $(shell find src -name '*.cpp') DEPENDS := $(SOURCES:%.cpp=build/%.d) BINARIES := $(SOURCES:%.cpp=build/%) -CLANG_TIDY_HEADERS := $(filter-out include/tao/pegtl/internal/endian_win.hpp include/tao/pegtl/internal/file_mapper_win32.hpp,$(HEADER)) $(filter-out src/test/pegtl/main.hpp,$(shell find src -name '*.hpp')) +CLANG_TIDY_HEADERS := $(filter-out include/tao/pegtl/internal/file_mapper_win32.hpp include/tao/pegtl/contrib/internal/endian_win.hpp,$(HEADERS)) UNIT_TESTS := $(filter build/src/test/%,$(BINARIES)) @@ -61,8 +61,8 @@ build/%.valgrind: build/% valgrind: $(UNIT_TESTS:%=%.valgrind) @echo "All $(words $(UNIT_TESTS)) valgrind tests passed." -build/%.clang-tidy: % - $(CLANG_TIDY) -extra-arg "-Iinclude" -extra-arg "-std=c++17" -checks=*,-fuchsia-*,-google-runtime-references,-google-runtime-int,-google-readability-todo,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-*-magic-numbers,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-macro-usage,-hicpp-no-array-decay,-hicpp-signed-bitwise,-modernize-raw-string-literal,-misc-sizeof-expression,-misc-non-private-member-variables-in-classes,-bugprone-sizeof-expression,-bugprone-exception-escape -warnings-as-errors=* $< 2>/dev/null +build/%.clang-tidy: % .clang-tidy + $(CLANG_TIDY) -quiet $< -- $(CXXSTD) -Iinclude $(CPPFLAGS) $(CXXFLAGS) 2>/dev/null @mkdir -p $(@D) @touch $@ @@ -72,7 +72,7 @@ clang-tidy: $(CLANG_TIDY_HEADERS:%=build/%.clang-tidy) $(SOURCES:%=build/%.clang .PHONY: clean clean: - @rm -rf build + @rm -rf build/* @find . -name '*~' -delete build/%.d: %.cpp Makefile diff --git a/packages/PEGTL/README.md b/packages/PEGTL/README.md index d9798a2260477fd6edf914fae582485250fce3e3..2b57955028ddacc5d5418558f98a2589c1fa6680 100644 --- a/packages/PEGTL/README.md +++ b/packages/PEGTL/README.md @@ -1,7 +1,7 @@ # Welcome to the PEGTL [](https://github.com/taocpp/PEGTL/releases/latest) -[](https://bintray.com/taocpp/public-conan/pegtl%3Ataocpp/_latestVersion) +[](https://bintray.com/conan/conan-center/taocpp-pegtl%3A_/_latestVersion) [](https://travis-ci.org/taocpp/PEGTL) [](https://ci.appveyor.com/project/taocpp/PEGTL) [](https://coveralls.io/github/taocpp/PEGTL) @@ -61,16 +61,18 @@ Each commit is automatically tested with multiple architectures, operating syste * Windows * Visual Studio 2017 (x86, x64) + * Visual Studio 2019 (x86, x64) * macOS (using libc++) * macOS 10.13, Xcode 9.4 - * macOS 10.14, Xcode 10.2 + * macOS 10.14, Xcode 10.3 + * macOS 10.14, Xcode 11.4 * Ubuntu 16.04 LTS (using libstdc++) - * GCC 7.x, 8.x - * Clang 5.x, 6.x, 7.x, 8.x + * GCC 7.x, 8.x, 9.x + * Clang 5.x, 6.x, 7.x, 8.x, 9.x, 10.x Additionally, each commit is checked with Clang's [Static Analyzer](https://clang-analyzer.llvm.org/), GCC's and Clang's [sanitizers](https://github.com/google/sanitizers), [`clang-tidy`](http://clang.llvm.org/extra/clang-tidy/), and [`valgrind`](http://valgrind.org/). Code coverage is automatically measured and the unit tests cover 100% of the core library code (for releases). @@ -79,11 +81,53 @@ Code coverage is automatically measured and the unit tests cover 100% of the cor Incompatible API changes are *only* allowed to occur between major versions. For details see the [changelog](doc/Changelog.md). -## Contact +## Thank You + +In appreciation of all contributions here are the people that have [directly contributed](https://github.com/taocpp/PEGTL/graphs/contributors) to the PEGTL and/or its development. + +[<img alt="andoma" src="https://avatars.githubusercontent.com/u/216384?s=117" width="117">](https://github.com/andoma) +[<img alt="bjoe" src="https://avatars.githubusercontent.com/u/727911?s=117" width="117">](https://github.com/bjoe) +[<img alt="bwagner" src="https://avatars.githubusercontent.com/u/447049?s=117" width="117">](https://github.com/bwagner) +[<img alt="cdiggins" src="https://avatars.githubusercontent.com/u/1759994?s=460&v=4?s=117" width="117">](https://github.com/cdiggins) +[<img alt="delpinux" src="https://avatars.githubusercontent.com/u/35096584?s=117" width="117">](https://github.com/delpinux) +[<img alt="dkopecek" src="https://avatars.githubusercontent.com/u/1353140?s=117" width="117">](https://github.com/dkopecek) +[<img alt="irrequietus" src="https://avatars.githubusercontent.com/u/231192?s=117" width="117">](https://github.com/irrequietus) +[<img alt="jedelbo" src="https://avatars.githubusercontent.com/u/572755?s=117" width="117">](https://github.com/jedelbo) +[<img alt="joelfrederico" src="https://avatars.githubusercontent.com/u/458871?s=117" width="117">](https://github.com/joelfrederico) +[<img alt="johelegp" src="https://avatars.githubusercontent.com/u/21071787?s=117" width="117">](https://github.com/johelegp) +[<img alt="jovermann" src="https://avatars.githubusercontent.com/u/6087443?s=117" width="117">](https://github.com/jovermann) +[<img alt="kneth" src="https://avatars.githubusercontent.com/u/1225363?s=117" width="117">](https://github.com/kneth) +[<img alt="kuzmas" src="https://avatars.githubusercontent.com/u/1858553?s=117" width="117">](https://github.com/kuzmas) +[<img alt="lambdafu" src="https://avatars.githubusercontent.com/u/1138455?s=117" width="117">](https://github.com/lambdafu) +[<img alt="lichray" src="https://avatars.githubusercontent.com/u/433009?s=117" width="117">](https://github.com/lichray) +[<img alt="michael-brade" src="https://avatars.githubusercontent.com/u/8768950?s=117" width="117">](https://github.com/michael-brade) +[<img alt="mkrupcale" src="https://avatars.githubusercontent.com/u/13936020?s=117" width="117">](https://github.com/mkrupcale) +[<img alt="newproggie" src="https://avatars.githubusercontent.com/u/162319?s=460&v=4?s=117" width="117">](https://github.com/newproggie) +[<img alt="obiwahn" src="https://avatars.githubusercontent.com/u/741109?s=117" width="117">](https://github.com/obiwahn) +[<img alt="ohanar" src="https://avatars.githubusercontent.com/u/1442822?s=117" width="117">](https://github.com/ohanar) +[<img alt="pauloscustodio" src="https://avatars.githubusercontent.com/u/70773?s=117" width="117">](https://github.com/pauloscustodio) +[<img alt="pleroux0" src="https://avatars.githubusercontent.com/u/39619854?s=117" width="117">](https://github.com/pleroux0) +[<img alt="quadfault" src="https://avatars.githubusercontent.com/u/30195320?s=117" width="117">](https://github.com/quadfault) +[<img alt="robertcampion" src="https://avatars.githubusercontent.com/u/4220569?s=117" width="117">](https://github.com/robertcampion) +[<img alt="samhocevar" src="https://avatars.githubusercontent.com/u/245089?s=117" width="117">](https://github.com/samhocevar) +[<img alt="sanssecours" src="https://avatars.githubusercontent.com/u/691989?s=117" width="117">](https://github.com/sanssecours) +[<img alt="sgbeal" src="https://avatars.githubusercontent.com/u/235303?s=117" width="117">](https://github.com/sgbeal) +[<img alt="skyrich62" src="https://avatars.githubusercontent.com/u/23705081?s=117" width="117">](https://github.com/skyrich62) +[<img alt="studoot" src="https://avatars.githubusercontent.com/u/799344?s=117" width="117">](https://github.com/studoot) +[<img alt="svenjo" src="https://avatars.githubusercontent.com/u/1538181?s=460&v=4?s=117" width="117">](https://github.com/svenjo) +[<img alt="wickedmic" src="https://avatars.githubusercontent.com/u/12001183?s=117" width="117">](https://github.com/wickedmic) +[<img alt="wravery" src="https://avatars.githubusercontent.com/u/6502881?s=117" width="117">](https://github.com/wravery) +[<img alt="zhihaoy" src="https://avatars.githubusercontent.com/u/43971430?s=117" width="117">](https://github.com/zhihaoy) + +## The Art of C++ The PEGTL is part of [The Art of C++](https://taocpp.github.io/). -We [are grateful](doc/Thank-You.md) for all support and contributions. +[<img alt="colinh" src="https://avatars.githubusercontent.com/u/113184?s=117" width="117">](https://github.com/colinh) +[<img alt="d-frey" src="https://avatars.githubusercontent.com/u/3956325?s=117" width="117">](https://github.com/d-frey) +[<img alt="uilianries" src="https://avatars.githubusercontent.com/u/4870173?s=117" width="117">](https://github.com/uilianries) + +## Contact For questions and suggestions regarding the PEGTL, success or failure stories, and any other kind of feedback, please feel free to open an issue or a PR on GitHub or contact the authors at `taocpp(at)icemx.net`. @@ -91,7 +135,7 @@ For questions and suggestions regarding the PEGTL, success or failure stories, a The PEGTL is certified [Open Source](http://www.opensource.org/docs/definition.html) software. It may be used for any purpose, including commercial purposes, at absolutely no cost. It is distributed under the terms of the [MIT license](http://www.opensource.org/licenses/mit-license.html) reproduced here. -> Copyright (c) 2007-2019 Dr. Colin Hirsch and Daniel Frey +> Copyright (c) 2007-2020 Dr. Colin Hirsch and Daniel Frey > > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: > diff --git a/packages/PEGTL/conanfile.py b/packages/PEGTL/conanfile.py deleted file mode 100644 index 39ae05aa1d9680c3f913fc3bde115b71ac924dce..0000000000000000000000000000000000000000 --- a/packages/PEGTL/conanfile.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from conans import ConanFile, CMake - -class PEGTLConan(ConanFile): - name = "pegtl" - description = "C++ header-only parser combinator library for creating PEG parsers" - homepage = "https://github.com/taocpp/PEGTL" - topics = ("conan", "taocpp", "pegtl", "peg", "grammar", "parsing") - url = homepage - license = "MIT" - author = "taocpp@icemx.net" - exports = "LICENSE" - exports_sources = "cmake/*", "include/*", "CMakeLists.txt" - settings = "build_type", "compiler", "os", "arch" - generators = "cmake" - no_copy_source = True - - def build(self): - pass - - def package(self): - cmake = CMake(self) - cmake.definitions["PEGTL_BUILD_TESTS"] = "OFF" - cmake.definitions["PEGTL_BUILD_EXAMPLES"] = "OFF" - cmake.definitions["PEGTL_INSTALL_DOC_DIR"] = "licenses" - cmake.configure() - cmake.install() - - def package_id(self): - self.info.header_only() diff --git a/packages/PEGTL/doc/Actions-and-States.md b/packages/PEGTL/doc/Actions-and-States.md index 0f65e55935b025b46396b238b16f86ce960a124f..ae234dc28007583c315f81b06205a7198dfb8dc1 100644 --- a/packages/PEGTL/doc/Actions-and-States.md +++ b/packages/PEGTL/doc/Actions-and-States.md @@ -59,8 +59,8 @@ An example for a simple action for a specific state might look like this. template<> struct my_action< my_rule > { - template< typename Input > - static void apply( const Input& in, my_state& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, my_state& s ) { // ... implement } @@ -93,8 +93,8 @@ struct my_action< tao::pegtl::any > // Implement an apply() function that will be called by // the PEGTL every time tao::pegtl::any matches during // the parsing run. - template< typename Input > - static void apply( const Input& in, std::string& out ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& out ) { // Get the portion of the original input that the // rule matched this time as string and append it @@ -103,8 +103,8 @@ struct my_action< tao::pegtl::any > } }; -template< typename Input > -std::string as_string( Input& in ) +template< typename ParseInput > +std::string as_string( ParseInput& in ) { // Set up the states, here a single std::string as that is // what our action requires as additional function argument. @@ -143,8 +143,8 @@ As seen above, the actual functions that are called when an action is applied ar template<> struct my_action< my_rule > { - template< typename Input > - static void apply( const Input& in, /* all the states */ ) + template< typename ActionInput > + static void apply( const ActionInput& in, /* all the states */ ) { // Called whenever matching my_rule during a parsing run // succeeds (and actions are not disabled). The argument @@ -166,12 +166,12 @@ For illustrative purposes, we will assume that the input passed to `apply()` is Any resemblance to real classes is not a coincidence, see `include/tao/pegtl/internal/action_input.hpp`. ```c++ -template< typename Input > +template< typename ParseInput > class action_input { public: - using input_t = Input; - using iterator_t = typename Input::iterator_t; + using input_t = ParseInput; + using iterator_t = typename ParseInput::iterator_t; bool empty() const noexcept; std::size_t size() const noexcept; @@ -187,7 +187,7 @@ public: pegtl::position position() const noexcept; // Not efficient with tracking_mode::lazy. - const Input& input() const noexcept; + const ParseInput& input() const noexcept; const iterator_t& iterator() const noexcept; }; ``` @@ -421,8 +421,8 @@ template<> struct my_action< my_rule > : tao::pegtl::change_states< new_state_1, new_state_2 > { - template< typename Input > - static void success( const Input&, new_state_1&, new_state_2&, /* the previous states*/ ) + template< typename ParseInput > + static void success( const ParseInput&, new_state_1&, new_state_2&, /* the previous states*/ ) { // Do whatever with both the new and the old states... } @@ -452,9 +452,9 @@ struct my_action< my_rule > rewind_mode M, template< typename... > class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& in, States&&... st ) + static bool match( ParseInput& in, States&&... st ) { // Call the function that would have been called otherwise, // in this case without changing anything... @@ -538,4 +538,4 @@ Note that deriving from `require_apply` or `require_apply0` is optional and usua See the [section on legacy-style action rules](Rule-Reference.md#action-rules). -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Changelog.md b/packages/PEGTL/doc/Changelog.md index 37b4184c7e05a19895e8aefb29f5023ed7ad4198..3198b38dfad39a10d59ff81600ee256c3b0ded67 100644 --- a/packages/PEGTL/doc/Changelog.md +++ b/packages/PEGTL/doc/Changelog.md @@ -9,13 +9,47 @@ * Updated required [CMake](https://cmake.org/) version to 3.8. * The macro `TAO_PEGTL_NAMESPACE` now contains the fully qualified namespace, e.g. `tao::pegtl`. * Replaced `tao::pegtl::input_error` with `std::system_error`. +* Moved the analysis function and header to contrib. +* Replaced `analysis_t` with more general and complete `rule_t` and `subs_t`. +* Added functions to visit all rules of a grammar. +* Added infrastructure and functions to measure rule coverage of a parsing run. +* Added [`must_if<>`](Errors-and-Exceptions.md#custom-exception-messages) + * Allows to define custom error messages for global errors. + * As a non-intrusive way to define global parse errors for a grammar retroactively. +* Moved rule `eolf` from inline namespace `tao::pegtl::ascii` to `tao::pegtl`. * Changed message of `tao::pegtl::parse_error` to no longer contain the position redundantly. +* Changed rules in `tao/pegtl/contrib/integer.hpp` to not accept redundant leading zeros. +* Added rules to `tao/pegtl/contrib/integer.hpp` that test unsigned values against a maximum. * Removed option of [state](Rule-Reference.md#state-s-r-)'s `S::success()` to have an extended signature to get access to the current `apply_mode`, `rewind_mode`, *action*- and *control* class (template). -* Added `[[nodiscard]]` to most non-void functions. +* Added `[[nodiscard]]` or `[[noreturn]]` to most non-void functions. * Removed compatibility macros starting with `TAOCPP_PEGTL_`. * Removed compatibility uppercase enumerators. * Removed compatibility `peek_byte()` member functions. * Removed compatibility header `changes.hpp` from contrib. +* Demoted UTF-16 and UTF-32 support to contrib. +* Demoted UINT-8, UINT-16, UINT-32 and UINT-64 support to contrib. +* Folded `contrib/counter.hpp` into `json_count.cpp`, count is superceded by coverage. +* Refactored demangling. + * Improves generated code to be shorter and more efficient. + * Removes the need for RTTI. + * Some broken/unknown compilers will use RTTI as a fallback, without demangling. +* Refactored parse tree type storage/handling. + * Removes the need for RTTI. + +## 2.8.2 + +Released 2020-04-05 + +* Fixed parse tree node generation to correctly remove intermediate nodes. + +## 2.8.1 + +Released 2019-08-06 + +* Added fallback symbol demangling if RTTI is disabled. +* Fixed missing `string_input<>` in amalgamated header. +* Fixed `discard_input*` actions to properly forward the apply mode. +* Fixed contrib HTTP grammar for chunked data. ## 2.8.0 @@ -546,4 +580,4 @@ Released 2008 Development of the PEGTL started in November 2007 as an experiment in C++0x. It is based on ideas from the YARD library by Christopher Diggins. -Copyright (c) 2007-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2007-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Contrib-and-Examples.md b/packages/PEGTL/doc/Contrib-and-Examples.md index f83cc6cf1d4e78cb45f312e0ce7a909d23124878..c4292ae83ed82089782a279c56bbef373c19080a 100644 --- a/packages/PEGTL/doc/Contrib-and-Examples.md +++ b/packages/PEGTL/doc/Contrib-and-Examples.md @@ -51,13 +51,6 @@ For all questions and remarks contact us at **taocpp(at)icemx.net**. * Changes the state. * Ready for production use but might be changed in the future. -###### `<tao/pegtl/contrib/counter.hpp>` - -* Control class for obtaining basic statistics from a parsing run, namely how often each rule - 1. was attempted to match, - 2. succeeded to match, - 3. failed to match. - ###### `<tao/pegtl/contrib/disable_action.hpp>` * Disables actions. @@ -186,8 +179,7 @@ Extends on `json_parse.cpp` by parsing JSON files into generic JSON data structu ###### `src/example/pegtl/json_count.cpp` -Shows how to use the included [counter control](#taopegtlcontribcounterhpp), here together with the JSON grammar from `<tao/pegtl/contrib/json.hpp>`. -Invoked with one or more JSON files as argument, will attempt to parse the files and print the statistics counters to `std::cout`. +Shows how to use a simple custom control to create some parsing statistics while parsing JSON files. ###### `src/example/pegtl/lua53_parse.cpp` @@ -206,12 +198,12 @@ The example shows how to choose which rules will produce a parse tree node, whic The output is in [DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) format and can be converted into a graph. ```sh -$ build/src/example/pegtl/parse_tree "(2*a + 3*b) / (4*n)" | dot -Tpng -o parse_tree.png +$ build/src/example/pegtl/parse_tree "(2*a + 3*b) / (4*n)" | dot -Tsvg -o parse_tree.svg ``` -The above will generate a PNG with a graphical representation of the parse tree. +The above will generate an SVG file with a graphical representation of the parse tree. - + ###### `src/example/pegtl/proto3.cpp` @@ -242,4 +234,4 @@ Uses the building blocks from `<tao/pegtl/contrib/unescape.hpp>` to show how to Shows how to use the included [tracer control](#taopegtlcontribtracerhpp), here together with the URI grammar from `<tao/pegtl/contrib/uri.hpp>`. Invoked with one or more URIs as command line arguments will attempt to parse the URIs while printing trace information to `std::cerr`. -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Control-and-Debug.md b/packages/PEGTL/doc/Control-and-Debug.md index af5ef5a6706263f6d787cb19d711da2e1d4714fa..c8817e611e8a84e2c7894da571b74798bf6edf7c 100644 --- a/packages/PEGTL/doc/Control-and-Debug.md +++ b/packages/PEGTL/doc/Control-and-Debug.md @@ -28,42 +28,44 @@ The `normal` control class template included with the PEGTL is used by default a template< typename Rule > struct normal { - template< typename Input, + static constexpr bool enable; // See Meta-Data-and-Visit.md + + template< typename ParseInput, typename... States > - static void start( const Input&, States&&... ); + static void start( const ParseInput&, States&&... ); - template< typename Input, + template< typename ParseInput, typename... States > - static void success( const Input&, States&&... ); + static void success( const ParseInput&, States&&... ); - template< typename Input, + template< typename ParseInput, typename... States > - static void failure( const Input&, States&&... ); + static void failure( const ParseInput&, States&&... ); - template< typename Input, + template< typename ParseInput, typename... States > - static void raise( const Input& in, States&&... ); + static void raise( const ParseInput& in, States&&... ); template< template< typename... > class Action, typename Iterator, - typename Input, + typename ParseInput, typename... States > - static auto apply( const Iterator& begin, const Input& in, States&&... st ) + static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) -> decltype( ... ); template< template< typename... > class Action, - typename Input, + typename ParseInput, typename... States > - static auto apply0( const Input&, States&&... st ) + static auto apply0( const ParseInput&, States&&... st ) -> decltype( ... ); template< apply_mode A, rewind_mode M, template< typename... > class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& in, States&&... st ); + static bool match( ParseInput& in, States&&... st ); }; ``` @@ -140,4 +142,4 @@ Just like the action class template, a custom control class template can be used The latter requires the use of a [custom action](Actions-and-States.md). Deriving the specialisation of the custom action for `my_rule` from `tao::pegtl::change_control< my_control >` will switch the current control to `my_control` before attempting to match `my_rule`. -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Errors-and-Exceptions.md b/packages/PEGTL/doc/Errors-and-Exceptions.md index d632031eaa47d3f2b1d092d36f5ef0afa652499b..7cd752ef7eb009d7489070f9286d447613113e58 100644 --- a/packages/PEGTL/doc/Errors-and-Exceptions.md +++ b/packages/PEGTL/doc/Errors-and-Exceptions.md @@ -12,12 +12,16 @@ Other exception classes can be used freely from actions and custom parsing rules ## Contents * [Local to Global Failure](#local-to-global-failure) + * [Intrusive Local to Global Failure](#intrusive-local-to-global-failure) + * [Non-Intrusive Local to Global Failure](#non-intrusive-local-to-global-failure) * [Global to Local Failure](#global-to-local-failure) * [Examples for Must Rules](#examples-for-must-rules) * [Custom Exception Messages](#custom-exception-messages) ## Local to Global Failure +### Intrusive Local to Global Failure + A local failure returned by a parsing rule is not necessarily propagated to the top, for example when the rule is * in a rule like `not_at<>`, `opt<>` or `star<>`, or @@ -31,6 +35,15 @@ It should be mentioned that `must< R >` is semantically equivalent to `sor< R, r In any case, the task of actually throwing an exception is delegated to the [control class'](Control-and-Debug.md) `raise()`. +Note that rules and actions can throw exceptions directly, meaning those are not generated from the [control class'](Control-and-Debug.md) `raise()`. + +### Non-Intrusive Local to Global Failure + +If a grammar does not contain any `must<>` rule(s) (or `raise<>`, `if_must<>`, ...), one can still convert a local failure for a rule into a global failure via `must_if<>`. +This helper allows one to create a [control class'](Control-and-Debug.md) and provide custom error messages for global failures. +If an error message is provided for a rule that would normally return a local failure, it is automatically converted to a global failure. +See [Custom Exception Messages](#custom-exception-messages) for more information. + ## Global to Local Failure To convert global failure to local failure, the grammar rules [`try_catch`](Rule-Reference.md#try_catch-r-) and [`try_catch_type`](Rule-Reference.md#try_catch_type-e-r-) can be used. @@ -97,66 +110,50 @@ The same use of `if_must<>` can be applied to the `literal` rule assuming that i ## Custom Exception Messages -By default, when using any `must<>` error points, the exceptions generated by the PEGTL use the demangled name of the failed parsing rule as descriptive part of the error message. This is often insufficient and one would like to provide more meaningful error messages. +By default, when using any `must<>` error points, the exceptions generated by the PEGTL use the demangled name of the failed parsing rule as descriptive part of the error message. +This is often insufficient and one would like to provide more meaningful error messages. -A practical technique to provide customised error message for all `must<>` error points uses a custom control class whose `raise()` uses a static string as error message. +A practical technique to provide customised error messages for all `must<>` error points uses the `must_if<>` helper. + +For an example of this method see `src/examples/pegtl/json_errors.hpp`, where all errors that might occur in the supplied JSON grammar are customised like this: ```c++ -template< typename Rule > -struct my_control - : tao::pegtl::normal< Rule > -{ - static const std::string error_message; - - template< typename Input, typename... States > - static void raise( const Input& in, States&&... ) - { - throw tao::pegtl::parse_error( error_message, in ); - } -}; -``` +template< typename > inline constexpr const char* error_message = nullptr; -Now only the `error_message` string needs to be specialised per error point as follows. +template<> inline constexpr auto error_message< tao::pegtl::json::text > = "no valid JSON"; -```c++ -template<> inline const std::string my_control< MyRule >::error_message = "expected ..."; -``` +template<> inline constexpr auto error_message< tao::pegtl::json::end_array > = "incomplete array, expected ']'"; +template<> inline constexpr auto error_message< tao::pegtl::json::end_object > = "incomplete object, expected '}'"; +template<> inline constexpr auto error_message< tao::pegtl::json::member > = "expected member"; +template<> inline constexpr auto error_message< tao::pegtl::json::name_separator > = "expected ':'"; +template<> inline constexpr auto error_message< tao::pegtl::json::array_element > = "expected value"; +template<> inline constexpr auto error_message< tao::pegtl::json::value > = "expected value"; -Since `raise()` is only instantiated for those rules for which `must<>` could trigger an exception, it is sufficient to provide specialisations of the error message string for those rules. -Furthermore, there will be a linker error for all rules for which the specialisation was forgotten although `raise()` could be called. -For an example of this method see `src/examples/pegtl/json_errors.hpp`, where all errors that might occur in the supplied JSON grammar are customised like this: +template<> inline constexpr auto error_message< tao::pegtl::json::digits > = "expected at least one digit"; +template<> inline constexpr auto error_message< tao::pegtl::json::xdigit > = "incomplete universal character name"; +template<> inline constexpr auto error_message< tao::pegtl::json::escaped > = "unknown escape sequence"; +template<> inline constexpr auto error_message< tao::pegtl::json::char_ > = "invalid character in string"; +template<> inline constexpr auto error_message< tao::pegtl::json::string::content > = "unterminated string"; +template<> inline constexpr auto error_message< tao::pegtl::json::key::content > = "unterminated key"; -```c++ -template<> inline const std::string errors< tao::pegtl::json::text >::error_message = "no valid JSON"; - -template<> inline const std::string errors< tao::pegtl::json::end_array >::error_message = "incomplete array, expected ']'"; -template<> inline const std::string errors< tao::pegtl::json::end_object >::error_message = "incomplete object, expected '}'"; -template<> inline const std::string errors< tao::pegtl::json::member >::error_message = "expected member"; -template<> inline const std::string errors< tao::pegtl::json::name_separator >::error_message = "expected ':'"; -template<> inline const std::string errors< tao::pegtl::json::array_element >::error_message = "expected value"; -template<> inline const std::string errors< tao::pegtl::json::value >::error_message = "expected value"; - -template<> inline const std::string errors< tao::pegtl::json::digits >::error_message = "expected at least one digit"; -template<> inline const std::string errors< tao::pegtl::json::xdigit >::error_message = "incomplete universal character name"; -template<> inline const std::string errors< tao::pegtl::json::escaped >::error_message = "unknown escape sequence"; -template<> inline const std::string errors< tao::pegtl::json::char_ >::error_message = "invalid character in string"; -template<> inline const std::string errors< tao::pegtl::json::string::content >::error_message = "unterminated string"; -template<> inline const std::string errors< tao::pegtl::json::key::content >::error_message = "unterminated key"; - -template<> inline const std::string errors< tao::pegtl::eof >::error_message = "unexpected character after JSON value"; -``` +template<> inline constexpr auto error_message< tao::pegtl::eof > = "unexpected character after JSON value"; -It is also possible to provide a default error message that will be chosen by the compiler in the absence of a specialised one as follows. +// As must_if can not take error_message as a template parameter directly, we need to wrap it: +struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; }; -```c++ -template< typename T > -inline const std::string my_control< T >::error_message = - "parse error matching " + tao::pegtl::internal::demangle< T >(); +template< typename Rule > using control = tao::pegtl::must_if< error >::control< Rule >; ``` -This is similar to the default behaviour, but one will not get a linker error in case as error point is missed. +Since `raise()` is only instantiated for those rules for which `must<>` could trigger an exception, it is sufficient to provide specialisations of the error message string for those rules. +Furthermore, there will be a compile-time error (i.e. a `static_assert`) for all rules for which the specialisation was forgotten although `raise()` could be called. + +The [control class](Control-and-Debug.md) provided by `must_if<>` also turns local failures into global failure if an error message is provided, i.e. if the error message is not `nullptr`. +This means that one can provide additional points in the grammar where a global failure is triggered, even when the grammar contains no `must<>` error points. + +`must_if<>` expects a wrapper for the error message as its first template parameter. +There is a second parameter for the base control class, which defaults to `tao::pegtl::normal`, and which can combine `must_if`'s control class with other control classes. It is advisable to choose the error points in the grammar with prudence. This choice becoming particularly cumbersome and/or resulting in a large number of error points might be an indication of the grammar needing some kind of simplification or restructuring. -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Getting-Started.md b/packages/PEGTL/doc/Getting-Started.md index aa87cda4779191855098b952847863eafbe2b5d0..d2ef73f544ed8e824f94101b2c967c789e9227bc 100644 --- a/packages/PEGTL/doc/Getting-Started.md +++ b/packages/PEGTL/doc/Getting-Started.md @@ -4,7 +4,7 @@ Since the PEGTL is a parser library, here is an "inverse hello world" example th rather than prints, the string `Hello, foo!` for any sequence of alphabetic ASCII characters `foo`. ```c++ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <string> @@ -52,8 +52,8 @@ namespace hello template<> struct action< name > { - template< typename Input > - static void apply( const Input& in, std::string& v ) + template< typename ParseInput > + static void apply( const ParseInput& in, std::string& v ) { v = in.string(); } @@ -101,4 +101,4 @@ Aborted (core dumped) Frequently an application will include a top-level `try-catch` block to handle the exception. -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Grammar-Analysis.md b/packages/PEGTL/doc/Grammar-Analysis.md index ad9070ce9c91f85943712e9a722030046e2e9902..fa5e17230df1130fe8b4415473588507057fe683 100644 --- a/packages/PEGTL/doc/Grammar-Analysis.md +++ b/packages/PEGTL/doc/Grammar-Analysis.md @@ -1,33 +1,33 @@ # Grammar Analysis -The PEGTL contains an `analyze()` function that checks a grammar for rules that can go into an infinite loop without consuming input. - -Unfortunately, given the expressive power of PEGs and the possibility of arbitrary custom combinator rules, it is impossible to detect *all* kinds of infinite loops. - -It does however catch most cases of left-recursion that are typical for grammars converted from CFGs or other formalisms that gracefully handle left-recursion. +The PEGTL contains an `analyze()` function that checks a grammar for rules that can enter an infinite loop without consuming input. ## Content -* [Rule Analysis](#rule-analysis) -* [Background](#background) -* [Custom Rules](#custom-rules) +* [Running](#running) +* [Example](#example) +* [Requirements](#requirements) +* [Limitations](#limitations) -## Rule Analysis +## Running -In order to run an analysis on a grammar it is necessary to explicitly include `<tao/pegtl/analyze.hpp>`. +In order to run an analysis on a grammar it is necessary to explicitly include `<tao/pegtl/contrib/analyze.hpp>`. Then call `tao::pegtl::analyze()` with the top-level grammar rule as template argument. ```c++ -#include <tao/pegtl/analyze.hpp> +#include <tao/pegtl/contrib/analyze.hpp> -const std::size_t issues_found = tao::pegtl::analyze< my_grammar >(); +const std::size_t issues = tao::pegtl::analyze< my_grammar >(); ``` -`analyze()` returns the number of issues found and writes some information about them to `std::cout`. +The `analyze()` function prints some information about the found issues to `std::cout` and returns the total number of issues found. +The output can be suppressed by passing `false` as sole function argument. Analysing a grammar is usually only done while developing and debugging a grammar, or after changing it. -Regarding the kinds of issues that are detected, consider the following example grammar rules. +## Example + +Regarding the kinds of issues that are detected, consider the following example rules. ```c++ struct bar; @@ -45,40 +45,83 @@ As shown by the example program `src/example/pegtl/analyze.cpp`, the grammar ana Due to the differences regarding back-tracking and non-deterministic behaviour, this kind of infinite loop is a frequent issue when translating a CFG into a PEG. -## Background +## Requirements -In order to look for infinite loops in a grammar, `analyze()` needs some information about all rules in the grammar. -This "information" consists of a classification of the rules according to the following enum, plus, for non-atomic rules, a list of the sub-rules. +The `analyze()` function operates on an abstract form of the grammar that is mostly equivalent to the original grammar regarding the possibility of infinite cycles without progress. -```c++ -// namespace tao::pegtl::analysis +This abstract form is obtained via specialisations of the `analyze_traits<>` class template which each must have exactly one of `analyze_any_traits`, `analyze_opt_traits`, `analyze_seq_traits` and `analyze_sor_traits` as public (direct or indirect) base class. + +Specialisations of the `analyze_traits<>` class template are appropriately implemented for all grammar rule classes included with the PEGTL. +This support automatically extends to all custom rules built "the usual way" via public inheritance of (combinations and specialisations of) rules included with the PEGTL. + +For true custom rules, i.e. rules that implement their own `match()` function, the following steps need to be taken for them to work with the grammar analysis. -enum class rule_type : char +1. The rule needs a `rule_t` that, usually for true custom rules, is a type alias for the grammar rule itself. +2. There needs to be a specialisation of the `analyze_traits<>` for the custom rule, with an additional first template parameter: + +Assuming a custom rule like the following + +```c++ +struct my_rule { - any, - opt, - seq, - sor + using rule_t = my_rule; + + template< typename Input > + bool match( Input& in ) + { + return /* Something that always consumes on success... */ ; + } }; ``` -This enum value and rule list are provided to `analyze()` via an `analyze_t` type member that all rules that are part of a grammar that is to be analysed with `analyze()` need to define. +the analyze traits need to be set up as + +```c++ +// In namespace TAO_PEGTL_NAMESPACE + +template< typename Name > +struct analyze_traits< Name, my_rule > + : analyze_any_traits<> +{}; +``` + +where the base class is chosen as follows. + +1. `analyze_any_traits<>` is used for rules that always consume when they succeed. +2. `analyze_opt_traits<>` is used for rules that (can also) succeed without consuming. +3. `analyze_seq_traits<>` is used for rules that, regarding their match behaviour, are equivalent to `seq<>`. +4. `analyze_sor_traits<>` is used for rules that, regarding their match behaviour, are equivalent to `sor<>`. + +If `my_rule` has rules, that it calls upon as sub-rules, as template parameters, these need to be passed as template parameters to the chosen base class. + +Note that the first template parameter `Name` is required by the analyse traits of some rules in order to facilitate their transcription in terms of the basic combinators `seq`, `sor` and `opt`. + +For example `R = plus< T >` is equivalent to `seq< T, opt< R > >`, and the corresponding specialisation of the analyse traits is as follows. + +```c++ + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::plus< Rules... > > + : analyze_traits< Name, typename seq< Rules..., opt< Name > >::rule_t > + {}; +``` + +Note how the specialisation is for `internal::plus` rather than `plus`. +The convention is that only the classes that actually implement `match()` define `rule_t`. +This greatly reduces both the number of classes that need to define `rule_t` as well as the number of required `analyze_traits` specialisations. + +Note further how `Name` is required to transform the implicitly iterative rule `plus` into an explicitly recursive form that only uses `seq` and `opt`. +The analyse traits have the task of simplifying the grammar in order to keep the core analysis algorithm as simple as possible. -The names of the enum values correspond to one of the PEGTL rule classes that has this rule type, however some rule types are used by many different classes. +Please consult `include/tao/pegtl/contrib/analyze_traits.hpp` for many examples of how to correctly set up analyse traits for more complex rules, in particular for rules that do not directly fall into one of the aforementioned four categories. -* `any` is for rules where "success implies consumption" is true; assumes bounded repetition of conjunction of sub-rules. -* `opt` is for rules where "success implies consumption" is false; assumes bounded repetition of conjunction of sub-rules. -* `seq` is for rules where consumption on success depends on non-zero bounded repetition of the conjunction of sub-rules. -* `sor` is for rules where consumption on success depends on non-zero bounded repetition of the disjunction of sub-rules. +For any further reaching questions regarding how to set up the traits for custom rules please contact the authors at **taocpp(at)icemx.net**. -At the beginning of an `analyze()` run the function `R::analyze_t::insert()` is called for all rules `R` in the grammar in order to insert the information about the rule `R` into a data structure. +## Limitations -## Custom Rules +It has been conjectured, but, given the expressive power of PEGs, not proven, that *all* potential infinite loops are correctly detected. -For custom rules it should usually be sufficient to follow the lead of the rules supplied with the PEGTL and define `analyze_t` to either `tao::pegtl::analysis::generic` or `tao::pegtl::analysis::counted`. -In both cases, the `rule_type` and the list of sub-rules must be supplied as template parameters. -Class `tao::pegtl::analysis::counted` additionally takes an integer argument `Count` with the assumption being that a count of zero indicates that everything the rule type is `opt` while a non-zero count uses the rule type given as template parameter. +In practice it appears to catch all cases of left-recursion that are typical for grammars converted from CFGs or other formalisms that gracefully handle left-recursion. -When a custom rule goes beyond what can be currently expressed and all other questions, please contact the authors at **taocpp(at)icemx.net**. +False positives are a theoretical problem in that, while relatively easy to trigger, they are not usually encountered when dealing with real world grammars. -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Inputs-and-Parsing.md b/packages/PEGTL/doc/Inputs-and-Parsing.md index 0066d35c62111bca3cc550747b2684f597c356bd..689f0938c74c7c99f6dec5555dd554839524b925 100644 --- a/packages/PEGTL/doc/Inputs-and-Parsing.md +++ b/packages/PEGTL/doc/Inputs-and-Parsing.md @@ -42,7 +42,7 @@ All classes and functions on this page are in namespace `tao::pegtl`. * [Nested Parsing](#nested-parsing) * [Incremental Input](#incremental-input) * [Buffer Size](#buffer-size) - * [Discard Input](#discard-input) + * [Discard Buffer](#discard-buffer) * [Custom Rules](#custom-rules) * [Custom Readers](#custom-readers) * [Buffer Details](#buffer-details) @@ -303,9 +303,9 @@ template< typename Rule, template< typename... > class Control = normal, apply_mode A = apply_mode::action, rewind_mode M = rewind_mode::required, - typename Input, + typename ParseInput, typename... States > -bool parse( Input& in, +bool parse( ParseInput& in, States&&... st ); ``` @@ -325,11 +325,11 @@ template< typename Rule, template< typename... > class Control = normal, apply_mode A = apply_mode::action, rewind_mode M = rewind_mode::required, - typename Outer, - typename Input, + typename OuterInput, + typename ParseInput, typename... States > -bool parse_nested( const Outer& oi, - Input& in, +bool parse_nested( const OuterInput& oi, + ParseInput& in, States&&... st ); ``` @@ -389,6 +389,10 @@ To prevent the buffer from overflowing, the `discard()` member function of class **Discarding invalidates all pointers to the input's data and MUST NOT be used where backtracking to before the discard might occur AND/OR nested within a rule for which an action with input can be called.** +Calling `discard()` on a non-buffered input is an empty method and will be optimised away completely. + +Usually you don't call `discard()` manually. Instead, one of the two following methods might be used. + #### Via Rules The [`discard`](Rule-Reference#discard) rule behaves just like the [`success`](Rule-Reference.md#success) rule but calls the discard function on the input before returning `true`. @@ -399,6 +403,7 @@ The `tao::pegtl::discard_input`, `tao::pegtl::discard_input_on_success` and `tao These actions are used in the usual way, by deriving a custom action class template specialisation from them. In the case of `discard_input`, the input is discarded unconditionally after every match attempt of the rule that the action is attached to. +As `discard_input` is based on the `match()` method, it is unaffected by enabling or disabling actions (which only applies to the `apply`/`apply0`-methods). The other two variants behave as implied by their respective names, keeping in mind that "failure" is to be understood as "local failure" (false), no discard is performed on global failure (exception). Similarly "unconditional" is wrt. success or local failure, not global failure. @@ -435,8 +440,8 @@ template<> struct my_action< rep< 4, must< xdigit > > : tao::pegtl::discard_input { - template< typename Input > - void apply( const Input& in, /* the states */ ) + template< typename ActionInput > + static void apply( const ActionInput& in, /* the states */ ) { assert( in.size() == 4 ); // process the 4 xdigits @@ -541,4 +546,4 @@ Trying to call any of those functions on `buffer_input<>`-based instances will l All input classes support [deduction guides](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction), e.g. instead of `file_input<> in( "filename.txt" )` one can use `file_input in( "filename.txt" )`. -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Installing-and-Using.md b/packages/PEGTL/doc/Installing-and-Using.md index d0b78a470eb3f5a24de38f1804d14612d6e2f7c5..ec4302e1314688def828e3c9f9737b5f0202c3bc 100644 --- a/packages/PEGTL/doc/Installing-and-Using.md +++ b/packages/PEGTL/doc/Installing-and-Using.md @@ -4,14 +4,12 @@ * [Requirements](#requirements) * [Installation Packages](#installation-packages) +* [Using Conan](#using-conan) * [Using CMake](#using-cmake) * [CMake Installation](#cmake-installation) * [`find_package`](#find_package) * [`add_subdirectory`](#add_subdirectory) * [Mixing `find_package` and `add_subdirectory`](#mixing-find_package-and-add_subdirectory) -* [Conan](#conan) - * [Using a development version](#using-a-development-version) - * [Developing with conan editable](#developing-with-conan-editable) * [Manual Installation](#manual-installation) * [Embedding the PEGTL](#embedding-the-pegtl) * [Embedding in Binaries](#embedding-in-binaries) @@ -36,6 +34,8 @@ on either It requires C++17, e.g. using the `--std=c++17` compiler switch. Using newer versions of the C++ standard is supported. +Larger projects will frequently require the `/bigobj` option when compiling with Visual Studio on Windows. + It should also work with other C++17 compilers on other Unix systems (or any sufficiently compatible platform). The PEGTL is written with an emphasis on clean code and is compatible with @@ -43,14 +43,27 @@ the `-pedantic`, `-Wall`, `-Wextra` and `-Werror` compiler switches. ## Installation Packages -Installation packages are available from several package managers. Note that some of the listed packages are not updated regularly. +Installation packages are available from several package managers. +Note that some of the listed packages are not updated regularly. [](https://repology.org/metapackage/pegtl) -### Other +## Using Conan + +You can download and install the PEGTL using the [Conan] package manager: + +```bash +conan install taocpp-pegtl/<version>@ +``` -* [Conan] -* [Spack] +where `<version>` is the version of the PEGTL you want to use. + +The `taocpp-pegtl` package in Conan is kept up to date by Conan team members +and community contributors. If the version is out-of-date, please +[create an issue or pull request](https://github.com/conan-io/conan-center-index) +on the Conan Center Index repository. + +For more options and ways to use Conan, please refer to the [Conan documentation]. ## Using CMake @@ -115,8 +128,8 @@ are also defined. ### Mixing `find_package` and `add_subdirectory` With the advent of improved methods of managing dependencies (such as [Conan], -[Spack], [CMake FetchContent]), multiple package inclusion methods needs to be -able to co-exist. +[CMake FetchContent]), multiple package inclusion methods needs to be able to +co-exist. If PEGTL was first included with `find_package` then subsequent calls to `add_subdirectory(path/to/PEGTL)` will skip over the body of the @@ -133,60 +146,7 @@ two different versions of PEGTL simultaneously and signalling a fatal error becomes the only practical way of handling the inclusion of multiple different PEGTL versions. -For more options and ways to use CMake, please refer to the -[CMake documentation]. - -Conan ---- - -The [PEGTL conan package](https://bintray.com/taocpp/public-conan/pegtl%3Ataocpp) is automatically updated when a release is made, and it should always be up to date with the latest official release. - -Simply add - -```ini -pegtl/<version>@taocpp/stable -``` - -as a dependency to your conan project where `<version>` is the version of PEGTL you want to use. - -### Using a development version - -If a not yet released PEGTL version is required, then PEGTL can be exported in its current state. - -```bash -mkdir build -conan install -if build -conan export-pkg -if build -bf build . pegtl/<version>@taocpp/devel -``` - -Then proceed by adding - -```ini -pegtl/<version>@taocpp/devel -``` - -as a dependency to your conan project. - -### Developing with conan editable - -If it is required to develop PEGTL alongside another library/application then the package can be put into editable mode with - -```bash -conan editable add . pegtl/<version>@taocpp/devel -``` - -If the editable layout has `[builddirs]` set correctly and one is using the `cmake_paths` or `cmake`generator - -```cmake -find_package(pegtl) -``` - -will work as expected. It will find the editable package and add it to the current CMake project. An editable package implies that it is under development so tests and examples will be automatically built unless `PEGTL_BUILD_TESTS` and `PEGTL_BUILD_EXAMPLES` are turned off. - -Caveats with the editable package: - -- Currently, if the package is included with `CONAN_PKG::pegtl` or used in a build system other than CMake then the tests and examples won't be built as the CMake config script is bypassed. -- CMake will compulsively rebuild tests and examples if the build directory is reconfigured from another directory. +For more options and ways to use CMake, please refer to the [CMake documentation]. ## Manual Installation @@ -285,12 +245,15 @@ In a Unix-shell, the following command will achieve this: $ make amalgamate ``` -The above will generate a `build/amalgamated/pegtl.hpp` which will consist of the headers `tao/pegtl.hpp`, `tao/pegtl/analyze.hpp`, their dependencies, and all headers in `tao/pegtl/contrib/` except for the headers in `tao/pegtl/contrib/icu/`. +The above will generate a `build/amalgamated/pegtl.hpp` which will consist of +the headers `tao/pegtl.hpp`, `tao/pegtl/analyze.hpp`, their dependencies, +and all headers in `tao/pegtl/contrib/` except for the headers in +`tao/pegtl/contrib/icu/`. -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey +[Conan]: https://conan.io/ +[Conan documentation]: https://docs.conan.io/ [CMake]: https://cmake.org/ [CMake documentation]: https://cmake.org/documentation/ [CMake FetchContent]: https://cmake.org/cmake/help/latest/module/FetchContent.html -[Conan]: https://bintray.com/taocpp/public-conan/pegtl%3Ataocpp -[Spack]: http://spack.readthedocs.io/en/latest/package_list.html#pegtl diff --git a/packages/PEGTL/doc/Meta-Data-and-Visit.md b/packages/PEGTL/doc/Meta-Data-and-Visit.md new file mode 100644 index 0000000000000000000000000000000000000000..e8c5f5223abe862508dab87112698284c40851a4 --- /dev/null +++ b/packages/PEGTL/doc/Meta-Data-and-Visit.md @@ -0,0 +1,92 @@ +# Meta Data and Visit + +Each rule has several type aliases that allow for automatic inspection of a grammar and all of its rules for multiple purposes. +Note that true custom rules, i.e. rules that implement custom `match()` functions, do **not** need to define these type aliases for parsing. +They are only required to support functions based on `visit()` and the [grammar analysis](Grammar-Analysis.md). + +* [Internals](#internals) +* [Rule Type](#rule-type) +* [Sub Rules](#sub-rules) +* [Grammar Visit](#grammar-visit) +* [Grammar Print](#grammar-print) +* [Rule Coverage](#rule-coverage) + +## Internals + +While accessible in the namespace `TAO_PEGTL_NAMESPACE`, which defaults to `tao::pegtl`, the [rules and combinators](Rule-Reference.md) included with the PEGTL all have their actual implementation in the sub-namespace `internal`. +For example the header `include/tao/pegtl/rules.hpp` shows how the user-facing rules are nothing more than forwarders to their `internal` implementation. + +The original motivation for this additional level of indirection was to prevent uninteded invocation of user-defined actions due to some PEGTL rules being built from exisiting rules instead of having a dedicated implementation. +For example consider `rep_min` from `include/tao/pegtl/internal/rep_min.hpp`. + +```c++ +template< unsigned Min, typename Rule, typename... Rules > +using rep_min = seq< rep< Min, Rule, Rules... >, star< Rule, Rules... > >; +``` + +The expansion of `rep_min` uses the sub-rule `star< Rule, Rules... >`. +If a grammar were to contain both `rep_min` and `star` with the same sub-rules, and an action were provided for `star` with these exact sub-rules, then the action would not only be called for the explicit occurrences of `star` in the grammar but *also* for the corresponding sub-rule of `rep_min`. + +The action invocation for the sub-rule of `rep_min` is considered surprising and undesirable because it exposes implementation details to the user, forces her to deal with them, and breaks her grammar if the implementation were to change. + +Therefore it is possible to selectively disable most of the [control](Control-and-Debug.md) functions, including the `apply`-functions that perform action invocation, on a rule-by-rule basis. +More precisely, the action and debug control functions are only invoked for a rule `R` when `control< R >::enable` is `true`. + +```c++ +template< typename Rule > +struct normal +{ + static constexpr bool enable = internal::enable_control< Rule >; + +// ... +}; +``` + +The default control class template `normal` defines `normal< R >::enable` in terms of `internal::enable_control< R >` which is `true` by default, but `false` for all rules in sub-namespace `internal`, thereby hiding all invocations of `internal` rules from all actions and most of the control class functions. + +The facilities documented on this page however do **not** hide the implementation details since, while debugging a grammar or a parsing run, it is essential to have a complete picture. + +## Rule Type + +For each rule `R`, the type alias `R::rule_t` is defined as the type of the class that actually implements the `match()` function. +This is usually the root of the inheritance hierarchy. + +Note that `R::rule_t` can be completely different from `R`. +For example while `seq< R >::rule_t` is `internal::seq< R >`, due to `seq<>` being not only equivalent to `success`, but also implemented in terms of it, `seq<>::rule_t` is actually `internal::success`. + +In each rule's implementation mapping section the [rule reference](Rule-Reference.md) shows how `rule_t` is defined depending on the template parameters. + +## Sub Rules + +For each rule `R`, the type alias `R::subs_t` is an instantiation of `type_list` with all the direct sub-rules of `R` as template parameters. + +For example `seq< R, S >::subs_t` is `type_list< R, S >` and `alpha::subs_t` is `type_list<>`. + +Note that for many rules with sub-rules the corresponding `subs_t` is not as might be expected. +For example `enable< R, S >::subs_t` is `type_list< internal::seq< R, S > >` instead of the probably expected `type_list< R, S >`. + +Please again consult the [Rule Reference](Rule-Reference.md) (or the source) for how `subs_t` is defined for all included rules. + +## Grammar Visit + +The `visit()` function uses `subs_t` to recursively find all sub-rules of a grammar and call a function for each of them. + +1. The first, explicit, template parameter of `visit()` is the starting rule of the grammar that is to be inspected. + +2. The second, explicit, template parameter of `visit()` is a class template `F` where, for every sub-rule `R`, `visit()` will call `F< R >::visit()`. + +All arguments given to `visit()` will be passed on to all `F< R >::visit()` calls. + +The header `include/tao/pegtl/contrib/visit_rt.hpp` contains a drop-in replacement for `visit()` called `visit_rt()` that uses a run-time data structure, rather than compile-time type lists, to make sure the visitor is called only once for every grammar rule. +This can be a advantageous when working with large grammars since it reduces the template instantiation depth by shifting some of the work from compile time to run time. +Unlike `visit()`, `visit_rt()` returns the number of rules visited. + +## Grammar Print + +TODO. + +## Rule Coverage + +TODO. + +Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Migration-Guide.md b/packages/PEGTL/doc/Migration-Guide.md index a63ee5b5e2c272c887446a8b677daf3dcf5bf076..ccbe64dad09a56632149765e2995260aa8574c18 100644 --- a/packages/PEGTL/doc/Migration-Guide.md +++ b/packages/PEGTL/doc/Migration-Guide.md @@ -54,4 +54,4 @@ Please contact the authors at `taocpp(at)icemx.net` for any further questions wh There were [many important changes](Changelog.md#100) leading up to version 1.0.0. Please contact the authors at `taocpp(at)icemx.net` for any further questions when updating the PEGTL. -Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Parse-Tree.md b/packages/PEGTL/doc/Parse-Tree.md index cc1f319239719325fdd0d571fb6d26dce316eb0e..59d5e6ec3f46da0f75f2375f0b15aadd052d1d91 100644 --- a/packages/PEGTL/doc/Parse-Tree.md +++ b/packages/PEGTL/doc/Parse-Tree.md @@ -154,18 +154,19 @@ struct basic_node using children_t = std::vector< std::unique_ptr< node_t > >; children_t children; - std::type_index id; + std::string_view type; std::string source; + bool is_root() const noexcept; + template< typename U > - bool is() const noexcept { return id == typeid( U ); } + bool is_type() const noexcept; - bool is_root() const noexcept; + template< typename U > + void set_type() noexcept; // precondition from here on: !is_root() - std::string name() const; - position begin() const; position end() const; @@ -217,16 +218,16 @@ struct my_node // All non-root nodes receive a call to start() when // a match is attempted for Rule in a parsing run... - template< typename Rule, typename Input, typename... States > - void start( const Input& in, States&&... st ); + template< typename Rule, typename ParseInput, typename... States > + void start( const ParseInput& in, States&&... st ); // ...and later a call to success() when the match succeeded... - template< typename Rule, typename Input, typename... States > - void success( const Input& in, States&&... st ); + template< typename Rule, typename ParseInput, typename... States > + void success( const ParseInput& in, States&&... st ); // ...or to failure() when a (local) failure was encountered. - template< typename Rule, typename Input, typename... States > - void failure( const Input& in, States&&... st ); + template< typename Rule, typename ParseInput, typename... States > + void failure( const ParseInput& in, States&&... st ); // After a call to success(), and the (optional) call to the selector's // transform() did not discard a node, it is passed to its parent node @@ -236,4 +237,4 @@ struct my_node }; ``` -Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Parse-Tree.png b/packages/PEGTL/doc/Parse-Tree.png deleted file mode 100644 index fcacd0611dbb67c7516dbc0df9c54211d21d3ae9..0000000000000000000000000000000000000000 Binary files a/packages/PEGTL/doc/Parse-Tree.png and /dev/null differ diff --git a/packages/PEGTL/doc/Parse-Tree.svg b/packages/PEGTL/doc/Parse-Tree.svg new file mode 100644 index 0000000000000000000000000000000000000000..87792aff99e338eda8df9b54e79f814561a902e1 --- /dev/null +++ b/packages/PEGTL/doc/Parse-Tree.svg @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.40.1 (0) + --> +<!-- Title: parse_tree Pages: 1 --> +<svg width="1063pt" height="367pt" + viewBox="0.00 0.00 1062.99 367.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 363.4802)"> +<title>parse_tree</title> +<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-363.4802 1058.9899,-363.4802 1058.9899,4 -4,4"/> +<!-- x0x1604e70 --> +<g id="node1" class="node"> +<title>x0x1604e70</title> +<ellipse fill="none" stroke="#000000" cx="632.8736" cy="-341.4802" rx="39.7935" ry="18"/> +<text text-anchor="middle" x="632.8736" y="-337.7802" font-family="Times,serif" font-size="14.00" fill="#000000">ROOT</text> +</g> +<!-- x0x1605200 --> +<g id="node2" class="node"> +<title>x0x1605200</title> +<ellipse fill="none" stroke="#000000" cx="632.8736" cy="-269.4802" rx="83.6854" ry="18"/> +<text text-anchor="middle" x="632.8736" y="-265.7802" font-family="Times,serif" font-size="14.00" fill="#000000">example::divide</text> +</g> +<!-- x0x1604e70->x0x1605200 --> +<g id="edge1" class="edge"> +<title>x0x1604e70->x0x1605200</title> +<path fill="none" stroke="#000000" d="M632.8736,-323.3116C632.8736,-315.6112 632.8736,-306.4546 632.8736,-297.8969"/> +<polygon fill="#000000" stroke="#000000" points="636.3737,-297.8935 632.8736,-287.8935 629.3737,-297.8935 636.3737,-297.8935"/> +</g> +<!-- x0x16053b0 --> +<g id="node3" class="node"> +<title>x0x16053b0</title> +<ellipse fill="none" stroke="#000000" cx="528.8736" cy="-197.4802" rx="75.2868" ry="18"/> +<text text-anchor="middle" x="528.8736" y="-193.7802" font-family="Times,serif" font-size="14.00" fill="#000000">example::plus</text> +</g> +<!-- x0x1605200->x0x16053b0 --> +<g id="edge2" class="edge"> +<title>x0x1605200->x0x16053b0</title> +<path fill="none" stroke="#000000" d="M607.963,-252.2344C594.199,-242.7055 576.9218,-230.7443 562.0293,-220.4341"/> +<polygon fill="#000000" stroke="#000000" points="563.7951,-217.3998 553.581,-214.5853 559.8106,-223.1551 563.7951,-217.3998"/> +</g> +<!-- x0x1605a60 --> +<g id="node4" class="node"> +<title>x0x1605a60</title> +<ellipse fill="none" stroke="#000000" cx="737.8736" cy="-197.4802" rx="94.4839" ry="18"/> +<text text-anchor="middle" x="737.8736" y="-193.7802" font-family="Times,serif" font-size="14.00" fill="#000000">example::multiply</text> +</g> +<!-- x0x1605200->x0x1605a60 --> +<g id="edge3" class="edge"> +<title>x0x1605200->x0x1605a60</title> +<path fill="none" stroke="#000000" d="M658.0237,-252.2344C671.8187,-242.775 689.109,-230.9188 704.0695,-220.6602"/> +<polygon fill="#000000" stroke="#000000" points="706.2969,-223.3767 712.5648,-214.8348 702.3381,-217.6036 706.2969,-223.3767"/> +</g> +<!-- x0x1605560 --> +<g id="node5" class="node"> +<title>x0x1605560</title> +<ellipse fill="none" stroke="#000000" cx="312.8736" cy="-116.6102" rx="94.4839" ry="18"/> +<text text-anchor="middle" x="312.8736" y="-112.9102" font-family="Times,serif" font-size="14.00" fill="#000000">example::multiply</text> +</g> +<!-- x0x16053b0->x0x1605560 --> +<g id="edge4" class="edge"> +<title>x0x16053b0->x0x1605560</title> +<path fill="none" stroke="#000000" d="M488.2457,-182.2692C453.5814,-169.2909 403.4996,-150.5404 365.7225,-136.3967"/> +<polygon fill="#000000" stroke="#000000" points="366.5019,-132.9513 355.9096,-132.7228 364.0475,-139.5069 366.5019,-132.9513"/> +</g> +<!-- x0x16057e0 --> +<g id="node6" class="node"> +<title>x0x16057e0</title> +<ellipse fill="none" stroke="#000000" cx="528.8736" cy="-116.6102" rx="94.4839" ry="18"/> +<text text-anchor="middle" x="528.8736" y="-112.9102" font-family="Times,serif" font-size="14.00" fill="#000000">example::multiply</text> +</g> +<!-- x0x16053b0->x0x16057e0 --> +<g id="edge5" class="edge"> +<title>x0x16053b0->x0x16057e0</title> +<path fill="none" stroke="#000000" d="M528.8736,-179.1296C528.8736,-169.1 528.8736,-156.4555 528.8736,-145.1666"/> +<polygon fill="#000000" stroke="#000000" points="532.3737,-144.8882 528.8736,-134.8882 525.3737,-144.8883 532.3737,-144.8882"/> +</g> +<!-- x0x16059d0 --> +<g id="node11" class="node"> +<title>x0x16059d0</title> +<ellipse fill="none" stroke="#000000" cx="737.8736" cy="-116.6102" rx="96.7474" ry="26.7407"/> +<text text-anchor="middle" x="737.8736" y="-120.4102" font-family="Times,serif" font-size="14.00" fill="#000000">example::integer</text> +<text text-anchor="middle" x="737.8736" y="-105.4102" font-family="Times,serif" font-size="14.00" fill="#000000">"4"</text> +</g> +<!-- x0x1605a60->x0x16059d0 --> +<g id="edge10" class="edge"> +<title>x0x1605a60->x0x16059d0</title> +<path fill="none" stroke="#000000" d="M737.8736,-179.1296C737.8736,-171.5597 737.8736,-162.5002 737.8736,-153.6583"/> +<polygon fill="#000000" stroke="#000000" points="741.3737,-153.4808 737.8736,-143.4808 734.3737,-153.4808 741.3737,-153.4808"/> +</g> +<!-- x0x1605b10 --> +<g id="node12" class="node"> +<title>x0x1605b10</title> +<ellipse fill="none" stroke="#000000" cx="953.8736" cy="-116.6102" rx="101.2327" ry="26.7407"/> +<text text-anchor="middle" x="953.8736" y="-120.4102" font-family="Times,serif" font-size="14.00" fill="#000000">example::variable</text> +<text text-anchor="middle" x="953.8736" y="-105.4102" font-family="Times,serif" font-size="14.00" fill="#000000">"n"</text> +</g> +<!-- x0x1605a60->x0x1605b10 --> +<g id="edge11" class="edge"> +<title>x0x1605a60->x0x1605b10</title> +<path fill="none" stroke="#000000" d="M780.8065,-181.4062C810.7205,-170.2065 851.2523,-155.0314 885.5715,-142.1824"/> +<polygon fill="#000000" stroke="#000000" points="886.9346,-145.4094 895.0725,-138.6252 884.4801,-138.8538 886.9346,-145.4094"/> +</g> +<!-- x0x16054d0 --> +<g id="node7" class="node"> +<title>x0x16054d0</title> +<ellipse fill="none" stroke="#000000" cx="96.8736" cy="-26.8701" rx="96.7474" ry="26.7407"/> +<text text-anchor="middle" x="96.8736" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">example::integer</text> +<text text-anchor="middle" x="96.8736" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">"2"</text> +</g> +<!-- x0x1605560->x0x16054d0 --> +<g id="edge6" class="edge"> +<title>x0x1605560->x0x16054d0</title> +<path fill="none" stroke="#000000" d="M273.2559,-100.1505C241.728,-87.0518 196.9923,-68.4657 160.464,-53.2895"/> +<polygon fill="#000000" stroke="#000000" points="161.4608,-49.9137 150.8832,-49.3091 158.7751,-56.378 161.4608,-49.9137"/> +</g> +<!-- x0x1605610 --> +<g id="node8" class="node"> +<title>x0x1605610</title> +<ellipse fill="none" stroke="#000000" cx="312.8736" cy="-26.8701" rx="101.2327" ry="26.7407"/> +<text text-anchor="middle" x="312.8736" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">example::variable</text> +<text text-anchor="middle" x="312.8736" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">"a"</text> +</g> +<!-- x0x1605560->x0x1605610 --> +<g id="edge7" class="edge"> +<title>x0x1605560->x0x1605610</title> +<path fill="none" stroke="#000000" d="M312.8736,-98.4499C312.8736,-88.5469 312.8736,-75.9148 312.8736,-64.0273"/> +<polygon fill="#000000" stroke="#000000" points="316.3737,-63.8597 312.8736,-53.8597 309.3737,-63.8597 316.3737,-63.8597"/> +</g> +<!-- x0x1605750 --> +<g id="node9" class="node"> +<title>x0x1605750</title> +<ellipse fill="none" stroke="#000000" cx="528.8736" cy="-26.8701" rx="96.7474" ry="26.7407"/> +<text text-anchor="middle" x="528.8736" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">example::integer</text> +<text text-anchor="middle" x="528.8736" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">"3"</text> +</g> +<!-- x0x16057e0->x0x1605750 --> +<g id="edge8" class="edge"> +<title>x0x16057e0->x0x1605750</title> +<path fill="none" stroke="#000000" d="M528.8736,-98.4499C528.8736,-88.5469 528.8736,-75.9148 528.8736,-64.0273"/> +<polygon fill="#000000" stroke="#000000" points="532.3737,-63.8597 528.8736,-53.8597 525.3737,-63.8597 532.3737,-63.8597"/> +</g> +<!-- x0x1605890 --> +<g id="node10" class="node"> +<title>x0x1605890</title> +<ellipse fill="none" stroke="#000000" cx="744.8736" cy="-26.8701" rx="101.2327" ry="26.7407"/> +<text text-anchor="middle" x="744.8736" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">example::variable</text> +<text text-anchor="middle" x="744.8736" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">"b"</text> +</g> +<!-- x0x16057e0->x0x1605890 --> +<g id="edge9" class="edge"> +<title>x0x16057e0->x0x1605890</title> +<path fill="none" stroke="#000000" d="M568.4914,-100.1505C599.7956,-87.1447 644.1211,-68.7291 680.5048,-53.6129"/> +<polygon fill="#000000" stroke="#000000" points="682.1617,-56.7147 690.0535,-49.6458 679.476,-50.2504 682.1617,-56.7147"/> +</g> +</g> +</svg> diff --git a/packages/PEGTL/doc/Performance-Notes.md b/packages/PEGTL/doc/Performance-Notes.md index 43198177dc0f998deec61a517b9ca73803296b7d..97cdfd8a5b9cc21e0bda87ed2b88d9734b25db6f 100644 --- a/packages/PEGTL/doc/Performance-Notes.md +++ b/packages/PEGTL/doc/Performance-Notes.md @@ -42,4 +42,4 @@ However with `-O0`, the optimised `at_one< '"' >` was faster by 5-10% in a [JSON We still need to test whether the compiler manages to perform the same optimisation in more complex cases. -Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/README.md b/packages/PEGTL/doc/README.md index 4f98196acd8814c5b1b92a783a4eefdfeedd6e2f..435f23193261a357715b02597dfa93a6c3148a3f 100644 --- a/packages/PEGTL/doc/README.md +++ b/packages/PEGTL/doc/README.md @@ -5,6 +5,7 @@ * [Installing and Using](Installing-and-Using.md) * [Requirements](Installing-and-Using.md#requirements) * [Installation Packages](Installing-and-Using.md#installation-packages) + * [Using Conan](Installing-and-Using.md#using-conan) * [Using CMake](Installing-and-Using.md#using-cmake) * [CMake Installation](Installing-and-Using.md#cmake-installation) * [`find_package`](Installing-and-Using.md#find_package) @@ -45,6 +46,8 @@ * [Legacy Actions](Actions-and-States.md#legacy-actions) * [Errors and Exceptions](Errors-and-Exceptions.md) * [Local to Global Failure](Errors-and-Exceptions.md#local-to-global-failure) + * [Intrusive Local to Global Failure](Errors-and-Exceptions.md#intrusive-local-to-global-failure) + * [Non-Intrusive Local to Global Failure](Errors-and-Exceptions.md#non-intrusive-local-to-global-failure) * [Global to Local Failure](Errors-and-Exceptions.md#global-to-local-failure) * [Examples for Must Rules](Errors-and-Exceptions.md#examples-for-must-rules) * [Custom Exception Messages](Errors-and-Exceptions.md#custom-exception-messages) @@ -76,7 +79,7 @@ * [Nested Parsing](Inputs-and-Parsing.md#nested-parsing) * [Incremental Input](Inputs-and-Parsing.md#incremental-input) * [Buffer Size](Inputs-and-Parsing.md#buffer-size) - * [Discard Input](Inputs-and-Parsing.md#discard-input) + * [Discard Buffer](Inputs-and-Parsing.md#discard-buffer) * [Custom Rules](Inputs-and-Parsing.md#custom-rules) * [Custom Readers](Inputs-and-Parsing.md#custom-readers) * [Buffer Details](Inputs-and-Parsing.md#buffer-details) @@ -95,16 +98,17 @@ * [Transformers](Parse-Tree.md#transformers) * [`tao::pegtl::parse_tree::node`](Parse-Tree.md#taopegtlparse_treenode) * [Custom Node Class](Parse-Tree.md#custom-node-class) +* [Meta Data and Visit](Meta-Data-and-Visit.md) * [Contrib and Examples](Contrib-and-Examples.md) * [Contrib](Contrib-and-Examples.md#contrib) * [Examples](Contrib-and-Examples.md#examples) * [Grammar Analysis](Grammar-Analysis.md) - * [Rule Analysis](Grammar-Analysis.md#rule-analysis) - * [Background](Grammar-Analysis.md#background) - * [Custom Rules](Grammar-Analysis.md#custom-rules) + * [Running](Grammar-Analysis.md#running) + * [Example](Grammar-Analysis.md#example) + * [Requirements](Grammar-Analysis.md#requirements) + * [Limitations](Grammar-Analysis.md#limitations) * [Changelog](Changelog.md) * [Migration Guide](Migration-Guide.md) -* [Thank You](Thank-You.md) # Rule Reference Index @@ -144,8 +148,8 @@ * [`east_asian_width< V >`](Rule-Reference.md#east_asian_width-v-) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-enumerated-properties)</sup> * [`enable< R... >`](Rule-Reference.md#enable-r-) <sup>[(meta-rules)](Rule-Reference.md#meta-rules)</sup> * [`eof`](Rule-Reference.md#eof) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup> -* [`eol`](Rule-Reference.md#eol) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup> -* [`eolf`](Rule-Reference.md#eolf) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup> +* [`eol`](Rule-Reference.md#eol) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup> +* [`eolf`](Rule-Reference.md#eolf) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup> * [`extender`](Rule-Reference.md#extender) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup> * [`failure`](Rule-Reference.md#failure) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup> * [`forty_two< C... >`](Rule-Reference.md#forty_two-c-) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup> @@ -283,4 +287,4 @@ * [`xid_continue`](Rule-Reference.md#xid_continue) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup> * [`xid_start`](Rule-Reference.md#xid_start) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup> -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Rule-Reference.md b/packages/PEGTL/doc/Rule-Reference.md index 85040484d959eca8015d4f6625538bd4f1001bdc..8464355a5ed3125ce0bf02a2300cd52818e8eb1b 100644 --- a/packages/PEGTL/doc/Rule-Reference.md +++ b/packages/PEGTL/doc/Rule-Reference.md @@ -13,15 +13,15 @@ Remember that there are two failure modes, only the first of which usually leads ## Equivalence -Some rule classes are said to be *equivalent* to a combination of other rules. -These rules are not completely equivalent to the shown definition because that -is not how they are implemented, therefore: +Some rule classes are said to be *equivalent to* a combination of other rules. +Here, *equivalence* is with respect to which inputs are matched, but not (necessarily) how the rule is implemented. -- Rule equivalence is with regard to which inputs will match, but: -- *not* with regard to which actions will be invoked while matching. +For rules other than `must<>` that contain "must" in their name, rule equivalence shows which rule will be used to call the control class' `raise()` function when certain sub-rules fail to match. -However, rule equivalence does show exactly where the `raise<>` rule is inserted -and therefore which rule will be used to call the control class' `raise()`. +## Implementation + +The "meta data and implementation mapping" section of each rule's description shows both how the rule is implemented and what the [meta data](Meta-Data-and-Visit.md) looks like. +When the list of sub-rules is empty then the definition of `subs_t` is omitted from the description. ## Parameter Packs @@ -53,49 +53,84 @@ These rules are in namespace `tao::pegtl`. ###### `action< A, R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Uses the given class template `A` for [actions](Actions-and-States.md). -* Actions can still be disabled explicitly (via `disable`) or implicitly (via `at` or `not_at`). +* Does not `enable` or `disable` actions while matching `R...`. +* [Meta data] and [implementation] mapping: + - `action< A >::rule_t` is `internal::success` + - `action< A, R >::rule_t` is `internal::action< A, R >` + - `action< A, R >::subs_t` is `type_list< R >` + - `action< A, R... >::rule_t` is `internal::action< A, internal::seq< R... > >` + - `action< A, R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `control< C, R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Uses the given class template `C` as [control class](Control-and-Debug.md). +* [Meta data] and [implementation] mapping: + - `control< C >::rule_t` is `internal::success` + - `control< C, R >::rule_t` is `internal::control< C, R >` + - `control< C, R >::subs_t` is `type_list< R >` + - `control< C, R... >:rule_t` is `internal::control< C, internal::seq< R... > >` + - `control< C, R... >:subs_t` is `type_list< internal::seq< R... > >` ###### `disable< R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Disables all actions. +* [Meta data] and [implementation] mapping: + - `disable<>::rule_t` is `internal::success` + - `disable< R >::rule_t` is `internal::disable<, R >` + - `disable< R >::subs_t` is `type_list< R >` + - `disable< R... >::rule_t` is `internal::disable< internal::seq< R... > >` + - `disable< R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `discard` -* Equivalent to `success`, but: +* [Equivalent] to `success`, but: * Calls the input's `discard()` member function. * Must not be used where backtracking to before the `discard` might occur and/or nested within a rule for which an action with input can be called. * See [Incremental Input](Inputs-and-Parsing.md#incremental-input) for details. +* [Meta data] and [implementation] mapping: + - `discard::rule_t` is `internal::discard` ###### `enable< R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Enables all actions (if any). +* [Meta data] and [implementation] mapping: + - `enable<>::rule_t` is `internal::success` + - `enable< R >::rule_t` is `internal::enable<, R >` + - `enable< R >::subs_t` is `type_list< R >` + - `enable< R... >::rule_t` is `internal::enable< internal::seq< R... > >` + - `enable< R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `require< Num >` * Succeeds if at least `Num` further input bytes are available. * With [Incremental Input](Inputs-and-Parsing.md#incremental-input) reads the bytes into the buffer. +* [Meta data] and [implementation] mapping: + - `require< 0 >::rule_t` is `internal::success` + - `require< N >::rule_t` is `internal::require< N >` ###### `state< S, R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Replaces all state arguments with a new instance `s` of type `S`. * `s` is constructed with the input and all previous states as arguments. * If `seq< R... >` succeeds then `s.success()` is called with the input after the match and all previous states as arguments. +* [Meta data] and [implementation] mapping: + - `state< S >::rule_t` is `internal::success` + - `state< S, R >::rule_t` is `internal::state< S, R >` + - `state< S, R >::subs_t` is `type_list< R >` + - `state< S, R... >::rule_t` is `internal::state< S, internal::seq< R... > >` + - `state< S, R... >::subs_t` is `type_list< internal::seq< R... > >` ## Combinators Combinators (or combinator rules) are rules that combine (other) rules into new ones. -These are the classical PEG combinator rules defined in namespace `tao::pegtl`. +These are the classical **PEG** combinator rules and are defined in namespace `tao::pegtl`. ###### `at< R... >` @@ -103,7 +138,12 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`. * Succeeds if and only if `seq< R... >` would succeed. * Consumes nothing, i.e. rewinds after matching. * Disables all actions. -* Allows local failure of `R...` even within `must<>` etc. +* [Meta data] and [implementation] mapping: + - `at<>::rule_t` is `internal::success` + - `at< R >::rule_t` is `internal::at< R >` + - `at< R >::subs_t` is `type_list< R >` + - `at< R... >::rule_t` is `internal::at< internal::seq< R... > >` + - `at< R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `not_at< R... >` @@ -111,21 +151,36 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`. * Succeeds if and only if `seq< R... >` would **not** succeed. * Consumes nothing, i.e. rewinds after matching. * Disables all actions. -* Allows local failure of `R...` even within `must<>` etc. +* [Meta data] and [implementation] mapping: + - `not_at<>::rule_t` is `internal::failure` + - `not_at< R >::rule_t` is `internal::not_at< R >` + - `not_at< R >::subs_t` is `type_list< R >` + - `not_at< R... >::rule_t` is `internal::not_at< internal::seq< R... > >` + - `not_at< R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `opt< R... >` * PEG **optional** *e*? * Optional `seq< R... >`, i.e. attempt to match `seq< R... >` and signal success regardless of the result. -* Equivalent to `sor< seq< R... >, success >`. -* Allows local failure of `R...` even within `must<>` etc. +* [Equivalent] to `sor< seq< R... >, success >`. +* [Meta data] and [implementation] mapping: + - `opt<>::rule_t` is `internal::success` + - `opt< R >::rule_t` is `internal::opt< R >` + - `opt< R >::subs_t` is `type_list< R >` + - `opt< R... >::rule_t` is `internal::opt< internal::seq< R... > >` + - `opt< R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `plus< R... >` * PEG **one-or-more** *e*+ * Matches `seq< R... >` as often as possible and succeeds if it matches at least once. -* Equivalent to `rep_min< 1, R... >`. +* [Equivalent] to `rep_min< 1, R... >`. * `R` must be a non-empty rule pack. +* [Meta data] and [implementation] mapping: + - `plus< R >::rule_t` is `internal::plus< R >` + - `plus< R >::subs_t` is `type_list< R >` + - `plus< R... >::rule_t` is `internal::plus< internal::seq< R... > >` + - `plus< R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `seq< R... >` @@ -135,6 +190,12 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`. * Fails and stops matching when one of the given rules fails. * Consumes everything that the rules `R...` consumed. * Succeeds if `R` is an empty rule pack. +* [Meta data] and [implementation] mapping: + - `seq<>::rule_t` is `internal::success` + - `seq< R >::rule_t` is `internal::seq< R >` + - `seq< R >::subs_t` is `type_list< R >` + - `seq< R... >::rule_t` is `internal::seq< R... >` + - `seq< R... >::subs_t` is `type_list< R... >` ###### `sor< R... >` @@ -143,15 +204,24 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`. * Matches the given rules `R...` in the given order. * Succeeds and stops matching when one of the given rules succeeds. * Consumes whatever the first rule that succeeded consumed. -* Allows local failure of `R...` even within `must<>` etc. * Fails if `R` is an empty rule pack. +* [Meta data] and [implementation] mapping: + - `sor<>::rule_t` is `internal::failure` + - `sor< R >::rule_t` is `internal::sor< R >` + - `sor< R >::subs_t` is `type_list< R >` + - `sor< R... >::rule_t` is `internal::sor< R... >` + - `sor< R... >::subs_t` is `type_list< R... >` ###### `star< R... >` * PEG **zero-or-more** *e** * Matches `seq< R... >` as often as possible and always succeeds. -* Allows local failure of `R...` even within `must<>` etc. * `R` must be a non-empty rule pack. +* [Meta data] and [implementation] mapping: + - `star< R >::rule_t` is `internal::star< R >` + - `star< R >::subs_t` is `type_list< R >` + - `star< R... >::rule_t` is `internal::star< internal::seq< R... > >` + - `star< R... >::subs_t` is `type_list< internal::seq< R... > >` ## Convenience @@ -164,133 +234,252 @@ These rules are in namespace `tao::pegtl`. ###### `if_must< R, S... >` * Attempts to match `R` and depending on the result proceeds with either `must< S... >` or `failure`. -* Equivalent to `seq< R, must< S... > >`. -* Equivalent to `if_then_else< R, must< S... >, failure >`. +* [Equivalent] to `seq< R, must< S... > >`. +* [Equivalent] to `if_then_else< R, must< S... >, failure >`. +* [Meta data] and [implementation] mapping: + - `if_must< R >::rule_t` is `internal::if_must< false, R >` + - `if_must< R >::subs_t` is `type_list< R >` + - `if_must< R, S... >::rule_t` is `internal::if_must< false, R, S... >` + - `if_must< R, S... >::subs_t` is `type_list< R, internal::must< S... > >` + +Note that the `false` template parameter to `internal::if_must` corresponds to the `failure` in the equivalent description using `if_then_else`. ###### `if_must_else< R, S, T >` * Attempts to match `R` and depending on the result proceeds with either `must< S >` or `must< T >`. -* Equivalent to `if_then_else< R, must< S >, must< T > >`. +* [Equivalent] to `if_then_else< R, must< S >, must< T > >`. +* [Meta data] and [implementation] mapping: + - `if_must_else< R, S, T >::rule_t` is `internal::if_then_else< R, internal::must< S >, internal::must< T > >` + - `if_must_else< R, S, T >::subs_t` is `type_list< R, internal::must< S >, internal::must< T > >` ###### `if_then_else< R, S, T >` -* Equivalent to `sor< seq< R, S >, seq< not_at< R >, T > >`. +* [Equivalent] to `sor< seq< R, S >, seq< not_at< R >, T > >`. +* [Meta data] and [implementation] mapping: + - `if_then_else< R, S, T >::rule_t` is `internal::if_then_else< R, S, T>` + - `if_then_else< R, S, T >::subs_t` is `type_list< R, S, T >` ###### `list< R, S >` * Matches a non-empty list of `R` separated by `S`. -* Equivalent to `seq< R, star< S, R > >`. +* [Equivalent] to `seq< R, star< S, R > >`. +* [Meta data] and [implementation] mapping: + - `list< R, S >::rule_t` is `internal::seq< R, internal::star< S, R > >` + - `list< R, S >::subs_t` is `type_list< R, internal::star< S, R > >` ###### `list< R, S, P >` * Matches a non-empty list of `R` separated by `S` where each `S` can be padded by `P`. -* Equivalent to `seq< R, star< pad< S, P >, R > >`. +* [Equivalent] to `seq< R, star< pad< S, P >, R > >`. +* [Meta data] and [implementation] mapping: + - `list< R, S, P >::rule_t` is `internal::seq< R, internal::star< internal::pad< S, P >, R > >` + - `list< R, S, P >::subs_t` is `type_list< R, internal::star< internal::pad< S, P >, R > >` ###### `list_must< R, S >` * Matches a non-empty list of `R` separated by `S`. * Similar to `list< R, S >`, but if there is an `S` it **must** be followed by an `R`. -* Equivalent to `seq< R, star< if_must< S, R > > >`. +* [Equivalent] to `seq< R, star< if_must< S, R > > >`. +* [Meta data] and [implementation] mapping: + - `list_must< R, S >::rule_t` is `internal::seq< R, internal::star< S, internal::must< R > > >` + - `list_must< R, S >::subs_t` is `type_list< R, internal::star< S, internal::must< R > > >` ###### `list_must< R, S, P >` * Matches a non-empty list of `R` separated by `S` where each `S` can be padded by `P`. * Similar to `list< R, S, P >`, but if there is an `S` it **must** be followed by an `R`. -* Equivalent to `seq< R, star< if_must< pad< S, P >, R > > >`. +* [Equivalent] to `seq< R, star< if_must< pad< S, P >, R > > >`. +* [Meta data] and [implementation] mapping: + - `list_must< R, S, P >::rule_t` is `internal::seq< R, internal::star< internal::pad< S, P >, internal::must< R > > >` + - `list_must< R, S, P >::subs_t` is `type_list< R, internal::star< internal::pad< S, P >, internal::must< R > > >` ###### `list_tail< R, S >` * Matches a non-empty list of `R` separated by `S` with optional trailing `S`. -* Equivalent to `seq< list< R, S >, opt< S > >`. +* [Equivalent] to `seq< list< R, S >, opt< S > >`. +* [Meta data] and [implementation] mapping: + - `list_tail< R, S >::rule_t` is `internal::seq< R, internal::star< S, R >, internal::opt< S > >` + - `list_tail< R, S >::subs_t` is `type_list< R, internal::star< S, R >, internal::opt< S > >` ###### `list_tail< R, S, P >` * Matches a non-empty list of `R` separated by `S` with optional trailing `S` and padding `P` inside the list. -* Equivalent to `seq< list< R, S, P >, opt< star< P >, S > >`. +* [Equivalent] to `seq< list< R, S, P >, opt< star< P >, S > >`. +* [Meta data] and [implementation] mapping: + - `list_tail< R, S, P >::rule_t` is `internal::seq< R, internal::star< internal::pad< S, P >, R >, internal::opt< internal::star< P >, S > >` + - `list_tail< R, S, P >::subs_t` is `type_list< R, internal::star< internal::pad< S, P >, R > >, internal::opt< internal::star< P >, S > >` ###### `minus< M, S >` * Succeeds if `M` matches, and `S` does *not* match *all* of the input that `M` matched. -* Equivalent to `rematch< M, not_at< S, eof > >`. +* [Equivalent] to `rematch< M, not_at< S, eof > >`. +* [Meta data] and [implementation] mapping: + - `minus< M, S >::rule_t` is `internal::rematch< M, internal::not_at< S, internal::eof > >` + - `minus< M, S >::subs_t` is `type_list< M, internal::not_at< S, internal::eof > >` ###### `must< R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Converts local failure of `R...` into global failure. * Calls `raise< R >` for the `R` that failed. -* Equivalent to `seq< sor< R, raise< R > >... >`. +* [Equivalent] to `seq< sor< R, raise< R > >... >`. +* [Meta data] and [implementation] mapping: + - `must<>::rule_t` is `internal::success` + - `must< R >::rule_t` is `internal::must< R >` + - `must< R >::subs_t` is `type_list< R >` + - `must< R... >::rule_t` is `internal::seq< internal::must< R >... >::rule_t` + - `must< R... >::subs_t` is `type_list< internal::must< R... > >` + +Note that `must` uses a different pattern to handle multiple sub-rules compared to the other `seq`-equivalent rules (which use `rule< seq< R... > >` rather than `seq< rule< R >... >`). ###### `opt_must< R, S... >` -* Equivalent to `opt< if_must< R, S... > >`. +* [Equivalent] to `opt< if_must< R, S... > >`. +* [Equivalent] to `if_then_else< R, must< S... >, success >`. +* [Meta data] and [implementation] mapping: + - `opt_must< R >::rule_t` is `internal::if_must< true, R >` + - `opt_must< R >::subs_t` is `type_list< R >` + - `opt_must< R, S... >::rule_t` is `internal::if_must< true, R, S... >` + - `opt_must< R, S... >::subs_t` is `type_list< R, internal::must< S... > >` + +Note that the `true` template parameter to `internal::if_must` corresponds to the `success` in the equivalent description using `if_then_else`. ###### `pad< R, S, T = S >` * Matches an `R` that can be padded by arbitrary many `S` on the left and `T` on the right. -* Equivalent to `seq< star< S >, R, star< T > >`. +* [Equivalent] to `seq< star< S >, R, star< T > >`. +* [Meta data] and [implementation] mapping: + - `pad< R, S, T >::rule_t` is `internal::seq< internal::star< S >, R, internal::star< T > >` + - `pad< R, S, T >::subs_t` is `type_list< internal::star< S >, R, internal::star< T > >` ###### `pad_opt< R, P >` * Matches an optional `R` that can be padded by arbitrary many `P` or just arbitrary many `P`. -* Equivalent to `seq< star< P >, opt< R, star< P > > >`. +* [Equivalent] to `seq< star< P >, opt< R, star< P > > >`. +* [Meta data] and [implementation] mapping: + - `pad_opt< R, P >::rule_t` is `internal::seq< internal::star< P >, internal::opt< R, internal::star< P > > >` + - `pad_opt< R, P >::subs_t` is `type_list< internal::star< P >, internal::opt< R, internal::star< P > > >` ###### `rematch< R, S... >` * Succeeds if `R` matches, and each `S` matches the input that `R` matched. * Ignores all `S` for the [grammar analysis](Grammar-Analysis.md). +* [Meta data] and [implementation] mapping: + - `rematch< R, S... >::rule_t` is `internal::rematch< R, S... >` + - `rematch< R, S... >::subs_t` is `type_list< R, S... >` ###### `rep< Num, R... >` * Matches `seq< R... >` for `Num` times without checking for further matches. -* Equivalent to `seq< seq< R... >, ..., seq< R... > >` where `seq< R... >` is repeated `Num` times. +* [Equivalent] to `seq< seq< R... >, ..., seq< R... > >` where `seq< R... >` is repeated `Num` times. +* [Meta data] and [implementation] mapping: + - `rep< 0, R... >::rule_t` is `internal::success` + - `rep< N >::rule_t` is `internal::success` + - `rep< N, R >::rule_t` is `internal::rep< N, R >` + - `rep< N, R >::subs_t` is `type_list< R >` + - `rep< N, R... >::rule_t` is `internal::rep< N, internal::seq< R... > >` + - `rep< N, R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `rep_max< Max, R... >` * Matches `seq< R... >` for at most `Max` times and verifies that it doesn't match more often. -* Equivalent to `rep_min_max< 0, Max, R... >`. +* [Equivalent] to `rep_min_max< 0, Max, R... >`. +* [Meta data] and [implementation] mapping: + - `rep_max< 0, R >::rule_t` is `internal::not_at< R >` + - `rep_max< 0, R >::subs_t` is `type_list< R >` + - `rep_max< 0, R... >::rule_t` is `internal::not_at< internal::seq< R... > >` + - `rep_max< 0, R... >::subs_t` is `type_list< internal::seq< R... > >` + - `rep_max< Max >::rule_t` is `internal::failure` + - `rep_max< Max, R >::rule_t` is `internal::rep_min_max< 0, Max, R >` + - `rep_max< Max, R >::subs_t` is `type_list< R >` + - `rep_max< Max, R... >::rule_t` is `internal::rep_min_max< 0, Max, internal::seq< R... > >` + - `rep_max< Max, R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `rep_min< Min, R... >` * Matches `seq< R... >` as often as possible and succeeds if it matches at least `Min` times. -* Equivalent to `seq< rep< Min, R... >, star< R... > >`. +* [Equivalent] to `seq< rep< Min, R... >, star< R... > >`. * `R` must be a non-empty rule pack. +* [Meta data] and [implementation] mapping: + - `rep_min< Min, R... >::rule_t` is `internal::seq< internal::rep< Min, R... >, internal::star< R... > >` + - `rep_min< Min, R... >::subs_t` is `type_list< internal::rep< Min, R... >, internal::star< R... > >` ###### `rep_min_max< Min, Max, R... >` * Matches `seq< R... >` for `Min` to `Max` times and verifies that it doesn't match more often. -* Equivalent to `seq< rep< Min, R... >, rep_opt< Max - Min, R... >, not_at< R... > >`. +* [Equivalent] to `seq< rep< Min, R... >, rep_opt< Max - Min, R... >, not_at< R... > >`. +* [Meta data] and [implementation] mapping: + - `rep_min_max< 0, 0, R >::rule_t` is `internal::not_at< R >` + - `rep_min_max< 0, 0, R >::subs_t` is `type_list< R >` + - `rep_min_max< 0, 0, R... >::rule_t` is `internal::not_at< internal::seq< R... > >` + - `rep_min_max< 0, 0, R... >::subs_t` is `type_list< internal::seq< R... > >` + - `rep_min_max< Min, Max >::rule_t` is `internal::failure` + - `rep_min_max< Min, Max, R >::rule_t` is `internal::rep_min_max< Min, Max, R >` + - `rep_min_max< Min, Max, R >::subs_t` is `type_list< R >` + - `rep_min_max< Min, Max, R... >::rule_t` is `internal::rep_min_max< Min, Max, internal::seq< R... > >` + - `rep_min_max< Min, Max, R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `rep_opt< Num, R... >` * Matches `seq< R... >` for zero to `Num` times without check for further matches. -* Equivalent to `rep< Num, opt< R... > >`. +* [Equivalent] to `rep< Num, opt< R... > >`. +* [Meta data] and [implementation] mapping: + - `rep_opt< 0, R... >::rule_t` is `internal::success` + - `rep_opt< Num >::rule_t` is `internal::success` + - `rep_opt< Num, R... >::rule_t` is `internal::seq< internal::rep< Num, R... >, internal::star< R... > >` + - `rep_opt< Num, R... >::subs_t` is `type_list< internal::rep< Num, R... >, internal::star< R... > >` ###### `star_must< R, S... >` -* Equivalent to `star< if_must< R, S... > >`. +* [Equivalent] to `star< if_must< R, S... > >`. +* [Meta data] and [implementation] mapping: + - `star_must< R >::rule_t` is `internal::star< internal::if_must< false, R > >` + - `star_must< R >::subs_t` is `type_list< internal::if_must< false, R > >` + - `star_must< R, S... >::rule_t` is `internal::star< internal::if_must< false, R, S... > >` + - `star_must< R, S... >::subs_t` is `type_list< internal::if_must< false, R, S... > >` ###### `try_catch< R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Converts global failure (exception) into local failure (return value `false`). * Catches exceptions of type `tao::pegtl::parse_error`. +* [Meta data] and [implementation] mapping: + - `try_catch<>::rule_t` is `internal::success` + - `try_catch< R >::rule_t` is `internal::try_catch_type< parse_error, R >` + - `try_catch< R >::subs_t` is `type_list< R >` + - `try_catch< R... >::rule_t` is `internal::try_catch_type< parse_error, internal::seq< R... > >` + - `try_catch< R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `try_catch_type< E, R... >` -* Equivalent to `seq< R... >`, but: +* [Equivalent] to `seq< R... >`, but: * Converts global failure (exception) into local failure (return value `false`). * Catches exceptions of type `E`. +* [Meta data] and [implementation] mapping: + - `try_catch_type< E >::rule_t` is `internal::success` + - `try_catch_type< E, R >::rule_t` is `internal::try_catch_type< E, R >` + - `try_catch_type< E, R >::subs_t` is `type_list< R >` + - `try_catch_type< E, R... >::rule_t` is `internal::try_catch_type< E, internal::seq< R... > >` + - `try_catch_type< E, R... >::subs_t` is `type_list< internal::seq< R... > >` ###### `until< R >` * Consumes all input until `R` matches. -* Equivalent to `until< R, any >`. +* [Equivalent] to `until< R, any >`. +* [Meta data] and [implementation] mapping: + - `until< R >::rule_t` is `internal::until< R >` + - `until< R >::subs_t` is `type_list< R >` ###### `until< R, S... >` * Matches `seq< S... >` as long as `at< R >` does not match and succeeds when `R` matches. -* Equivalent to `seq< star< not_at< R >, not_at< eof >, S... >, R >`. +* [Equivalent] to `seq< star< not_at< R >, not_at< eof >, S... >, R >`. * Does not apply if `S` is an empty rule pack, see the previous entry for the semantics of `until< R >`. +* [Meta data] and [implementation] mapping: + - `until< R, S >::rule_t` is `internal::until< R, S >` + - `until< R, S >::subs_t` is `type_list< R, S >` + - `until< R, S... >::rule_t` is `internal::until< R, internal::seq< S... > >` + - `until< R, S... >::subs_t` is `type_list< R, internal::seq< S... > >` ## Action Rules @@ -298,25 +487,32 @@ These rules are in namespace `tao::pegtl`. These rules replicate the intrusive way actions were called from within the grammar in the PEGTL 0.x with the `apply<>` and `if_apply<>` rules. The actions for these rules are classes (rather than class templates as required for `parse()` and the `action<>`-rule). -These rules respect the current `apply_mode`, but don't use the control-class to invoke the actions. +These rules respect the current `apply_mode`, but do **not** use the control class to invoke the actions. ###### `apply< A... >` * Calls `A::apply()` for all `A`, in order, with an empty input and all states as arguments. * If any `A::apply()` has a boolean return type and returns `false`, no further `A::apply()` calls are made and the result is equivalent to `failure`, otherwise: -* Equivalent to `success` wrt. parsing. +* [Equivalent] to `success` wrt. parsing. +* [Meta data] and [implementation] mapping: + - `apply< A... >::rule_t` is `internal::apply< A... >` ###### `apply0< A... >` * Calls `A::apply0()` for all `A`, in order, with all states as arguments. * If any `A::apply0()` has a boolean return type and returns `false`, no further `A::apply0()` calls are made and the result is equivalent to `failure`, otherwise: -* Equivalent to `success` wrt. parsing. +* [Equivalent] to `success` wrt. parsing. +* [Meta data] and [implementation] mapping: + - `apply0< A... >::rule_t` is `internal::apply0< A... >` ###### `if_apply< R, A... >` -* Equivalent to `seq< R, apply< A... > >` wrt. parsing, but also: +* [Equivalent] to `seq< R, apply< A... > >` wrt. parsing, but also: * If `R` matches, calls `A::apply()`, for all `A`, in order, with the input matched by `R` and all states as arguments. * If any `A::apply()` has a boolean return type and returns `false`, no further `A::apply()` calls are made. +* [Meta data] and [implementation] mapping: + - `if_apply< R, A... >::rule_t` is `internal::if_apply< R, A... >` + - `if_apply< R, A... >::subs_t` is `type_list< R >` ## Atomic Rules @@ -329,27 +525,52 @@ Atomic rules do not rely on other rules. * Succeeds at "beginning-of-file", i.e. when the input's `byte()` member function returns zero. * Does not consume input. * Does **not** work with inputs that don't have a `byte()` member function. +* [Meta data] and [implementation] mapping: + - `bof::rule_t` is `internal::bof` ###### `bol` * Succeeds at "beginning-of-line", i.e. when the input's `byte_in_line()` member function returns zero. * Does not consume input. * Does **not** work with inputs that don't have a `byte_in_line()` member function. +* [Meta data] and [implementation] mapping: + - `bol::rule_t` is `internal::bol` ###### `bytes< Num >` * Succeeds when the input contains at least `Num` further bytes. * Consumes these `Num` bytes from the input. +* [Meta data] and [implementation] mapping: + - `bytes< 0 >::rule_t` is `internal::success` + - `bytes< Num >::rule_t` is `internal::bytes< Num >` ###### `eof` * Succeeds at "end-of-file", i.e. when the input is empty or all input has been consumed. * Does not consume input. +* [Meta data] and [implementation] mapping: + - `eof::rule_t` is `internal::eof` + +###### `eol` + +* Depends on the `Eol` template parameter of the input, by default: +* Matches and consumes a Unix or MS-DOS line ending, that is: +* [Equivalent] to `sor< one< '\n' >, string< '\r', '\n' > >`. +* [Meta data] and [implementation] mapping: + - `eol::rule_t` is `internal::eol` + +###### `eolf` + +* [Equivalent] to `sor< eof, eol >`. +* [Meta data] and [implementation] mapping: + - `eolf::rule_t` is `internal::eolf` ###### `failure` * Dummy rule that never succeeds. * Does not consume input. +* [Meta data] and [implementation] mapping: + - `failure::rule_t` is `internal::failure` ###### `raise< T >` @@ -357,11 +578,15 @@ Atomic rules do not rely on other rules. * Calls the control-class' `Control< T >::raise()` static member function. * `T` *can* be a rule, but it does not have to be a rule. * Does not consume input. +* [Meta data] and [implementation] mapping: + - `raise< T >::rule_t` is `internal::raise< T >` ###### `success` * Dummy rule that always succeeds. * Does not consume input. +* [Meta data] and [implementation] mapping: + - `success::rule_t` is `internal::success` ## ASCII Rules @@ -377,97 +602,124 @@ and all possible byte values excluding `'a'`, respectively. However the characte for example the Euro sign code point `U+20AC`, which is encoded by the UTF-8 sequence `E2 82 AC`, can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao::pegtl::utf8::one< 0x20ac >`.) +ASCII rules do not usually rely on other rules. + ###### `alnum` * Matches and consumes a single ASCII alphabetic or numeric character. -* Equivalent to `ranges< 'a', 'z', 'A', 'Z', '0', '9' >`. +* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z', '0', '9' >`. +* [Meta data] and [implementation] mapping: + - `ascii::alnum::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9' >` ###### `alpha` * Matches and consumes a single ASCII alphabetic character. -* Equivalent to `ranges< 'a', 'z', 'A', 'Z' >`. +* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z' >`. +* [Meta data] and [implementation] mapping: + - `ascii::alpha::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z' >` ###### `any` * Matches and consumes any single byte, including all ASCII characters. -* Equivalent to `bytes< 1 >`. +* [Equivalent] to `bytes< 1 >`. +* [Meta data] and [implementation] mapping: + - `ascii::any::rule_t` is `internal::any< internal::peek_char >` ###### `blank` * Matches and consumes a single ASCII horizontal space or horizontal tabulator character. -* Equivalent to `one< ' ', '\t' >`. +* [Equivalent] to `one< ' ', '\t' >`. +* [Meta data] and [implementation] mapping: + - `ascii::blank::rule_t` is `internal::one< internal::result_on_found::success, internal::peek_char, ' ', '\t' >` ###### `digit` * Matches and consumes a single ASCII decimal digit character. -* Equivalent to `range< '0', '9' >`. +* [Equivalent] to `range< '0', '9' >`. +* [Meta data] and [implementation] mapping: + - `ascii::digit::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, '0', '9' >` ###### `ellipsis` * Matches and consumes three dots. -* Equivalent to `three< '.' >`. - -###### `eol` - -* Depends on the `Eol` template parameter of the input, by default: -* Matches and consumes a Unix or MS-DOS line ending, that is: -* Equivalent to `sor< one< '\n' >, string< '\r', '\n' > >`. - -###### `eolf` - -* Equivalent to `sor< eof, eol >`. +* [Equivalent] to `three< '.' >`. +* [Meta data] and [implementation] mapping: + - `ascii::ellipsis::rule_t` is `internal::string< '.', '.', '.' >` ###### `forty_two< C... >` -* Equivalent to `rep< 42, one< C... > >`. +* [Equivalent] to `rep< 42, one< C... > >`. +* [Meta data] and [implementation] mapping: + - `ascii::forty_two< C >::rule_t` is `internal_rep< 42, internal::one< internal::result_on_found::success, internal::peek_char, C > >` ###### `identifier_first` * Matches and consumes a single ASCII character permissible as first character of a C identifier. -* Equivalent to `ranges< 'a', 'z', 'A', 'Z', '_' >`. +* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z', '_' >`. +* [Meta data] and [implementation] mapping: + - `ascii::identifier_first::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '_' >` ###### `identifier_other` * Matches and consumes a single ASCII character permissible as subsequent character of a C identifier. -* Equivalent to `ranges< 'a', 'z', 'A', 'Z', '0', '9', '_' >`. +* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z', '0', '9', '_' >`. +* [Meta data] and [implementation] mapping: + - `ascii::identifier_first::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9', '_' >` ###### `identifier` * Matches and consumes an ASCII identifier as defined for the C programming language. -* Equivalent to `seq< identifier_first, star< identifier_other > >`. +* [Equivalent] to `seq< identifier_first, star< identifier_other > >`. +* [Meta data] and [implementation] mapping: + - `ascii::identifier::rule_t` is `internal::seq< identifier_first, internal::star< identifier_other > >`. ###### `istring< C... >` * Matches and consumes the given ASCII string `C...` with case insensitive matching. * Similar to `string< C... >`, but: * For ASCII letters a-z and A-Z the match is case insensitive. +* [Meta data] and [implementation] mapping: + - `ascii::istring<>::rule_t` is `internal::success` + - `ascii::istring< C... >::rule_t` is `internal::istring< C... >` ###### `keyword< C... >` -* Matches and consumes a non-empty string not followed by a subsequent identifier character. -* Equivalent to `seq< string< C... >, not_at< identifier_other > >`. +* Matches and consumes a non-empty string not followed by an identifier character. +* [Equivalent] to `seq< string< C... >, not_at< identifier_other > >`. +* `C` must be a non-empty character pack. +* [Meta data] and [implementation] mapping: + - `ascii::keyword< C... >::rule_t` is `internal::seq< internal::string< C... >, internal::not_at< internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9', '_' > > >` ###### `lower` * Matches and consumes a single ASCII lower-case alphabetic character. -* Equivalent to `range< 'a', 'z' >`. +* [Equivalent] to `range< 'a', 'z' >`. +* [Meta data] and [implementation] mapping: + - `ascii::lower::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 'a', 'z' >` ###### `not_one< C... >` * Succeeds when the input is not empty, and: * `C` is an empty character pack or the next input byte is **not** one of `C...`. * Consumes one byte when it succeeds. +* [Meta data] and [implementation] mapping: + - `ascii::not_one<>::rule_t` is `internal::any< internal::peek_char >` + - `ascii::not_one< C... >::rule_t` is `internal::one< result_on_found::failure, internal::peek_char, C... >` ###### `not_range< C, D >` * Succeeds when the input is not empty, and: * The next input byte is **not** in the closed range `C ... D`. * Consumes one byte when it succeeds. +* [Meta data] and [implementation] mapping: + - `ascii::not_range< C, C >::rule_t` is `internal::one< result_on_found::failure, internal::peek_char, C >` + - `ascii::not_range< C, D >::rule_t` is `internal::range< result_on_found::failure, internal::peek_char, C, D >` ###### `nul` * Matches and consumes an ASCII nul character. -* Equivalent to `one< 0 >`. +* [Equivalent] to `one< '\0' >`. + - `ascii::nul::rule_t` is `internal::one< result_on_found::success, internal::peek_char, 0 >` ###### `one< C... >` @@ -475,44 +727,63 @@ can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao * The next input byte is one of `C...`. * Consumes one byte when it succeeds. * Fails if `C` is an empty character pack. +* [Meta data] and [implementation] mapping: + - `ascii::not_one<>::rule_t` is `internal::failure` + - `ascii::not_one< C... >::rule_t` is `internal::one< result_on_found::success, internal::peek_char, C... >` ###### `print` * Matches and consumes any single ASCII character traditionally defined as printable. -* Equivalent to `range< 32, 126 >`. +* [Equivalent] to `range< 32, 126 >`. +* [Meta data] and [implementation] mapping: + - `ascii::print::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 32, 126 >` ###### `range< C, D >` * Succeeds when the input is not empty, and: * The next input byte is in the closed range `C ... D`. * Consumes one byte when it succeeds. +* [Meta data] and [implementation] mapping: + - `ascii::range< C, C >::rule_t` is `internal::one< result_on_found::success, internal::peek_char, C >` + - `ascii::range< C, D >::rule_t` is `internal::range< result_on_found::success, internal::peek_char, C, D >` ###### `ranges< C1, D1, C2, D2, ... >` - -* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ... >`. - ###### `ranges< C1, D1, C2, D2, ..., E >` -* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`. +* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ... >`. +* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`. +* [Meta data] and [implementation] mapping: + - `ascii::ranges<>::rule_t` is `internal::failure` + - `ascii::ranges< E >::rule_t` is `internal::one< result_on_found::success, internal::peek_char, E >` + - `ascii::ranges< C, D >::rule_t` is `internal::range< result_on_found::success, internal::peek_char, C, D >` + - `ascii::ranges< C... >::rule_t` is `internal::ranges< internal::peek_char, C... >` ###### `seven` * Matches and consumes any single true ASCII character that fits into 7 bits. -* Equivalent to `range< 0, 127 >`. +* [Equivalent] to `range< 0, 127 >`. +* [Meta data] and [implementation] mapping: + - `ascii::seven::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 0, 127 >` ###### `shebang` -* Equivalent to `seq< string< '#', '!' >, until< eolf > >`. +* [Equivalent] to `if_must< string< '#', '!' >, until< eolf > >`. ###### `space` * Matches and consumes a single space, line-feed, carriage-return, horizontal-tab, vertical-tab or form-feed. -* Equivalent to `one< ' ', '\n', '\r', '\t', '\v', '\f' >`. +* [Equivalent] to `one< ' ', '\n', '\r', '\t', '\v', '\f' >`. +* [Meta data] and [implementation] mapping: + - `ascii::shebang::rule_t` is `internal::seq< false, internal::string< '#', '!' >, internal::until< internal::eolf > >` + - `ascii::shebang::subs_t` is `type_list< internal::string< '#', '!' >, internal::until< internal::eolf > >` ###### `string< C... >` * Matches and consumes a string, a sequence of bytes or single-byte characters. -* Equivalent to `seq< one< C >... >`. +* [Equivalent] to `seq< one< C >... >`. +* [Meta data] and [implementation] mapping: + - `ascii::string<>::rule_t` is `internal::success` + - `ascii::string< C... >::rule_t` is `internal::string< C... >` ###### `TAO_PEGTL_ISTRING( "..." )` @@ -540,22 +811,30 @@ can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao * Succeeds when the input contains at least three bytes, and: * These three input bytes are all `C`. * Consumes three bytes when it succeeds. +* [Meta data] and [implementation] mapping: + - `ascii::three< C >::rule_t` is `internal::string< C, C, C >` ###### `two< C >` * Succeeds when the input contains at least two bytes, and: * These two input bytes are both `C`. * Consumes two bytes when it succeeds. +* [Meta data] and [implementation] mapping: + - `ascii::two< C >::rule_t` is `internal::string< C, C >` ###### `upper` * Matches and consumes a single ASCII upper-case alphabetic character. -* Equivalent to `range< 'A', 'Z' >`. +* [Equivalent] to `range< 'A', 'Z' >`. +* [Meta data] and [implementation] mapping: + - `ascii::upper::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 'A', 'Z' >` ###### `xdigit` * Matches and consumes a single ASCII hexadecimal digit character. -* Equivalent to `ranges< '0', '9', 'a', 'f', 'A', 'F' >`. +* [Equivalent] to `ranges< '0', '9', 'a', 'f', 'A', 'F' >`. +* [Meta data] and [implementation] mapping: + - `ascii::xdigit::rule_t` is `internal::ranges< internal::peek_char, '0', '9', 'a', 'f', 'A', 'F' >` ## Unicode Rules @@ -576,8 +855,11 @@ The following limitations apply to the UTF-16 and UTF-32 rules: * Unaligned input leads to unaligned memory access. * The line and column numbers are not counted correctly. +* They are not automatically included with `tao/pegtl.hpp`. -Unaligned memory is no problem on x86 compatible processors; on some other architectures like ARM an unaligned access will crash the application. +The UTF-16 and UTF-32 rules need to be manually included from their corresponding headers in the `contrib` section. + +Unaligned memory is no problem on x86 compatible processors; on ARM and most other architectures an unaligned access will crash the application. In the following descriptions a Unicode code point is considered *valid* when it is in the range `0` to `0x10ffff`. The parameter N stands for the size of the encoding of the next Unicode code point in the input, i.e. @@ -588,6 +870,8 @@ The parameter N stands for the size of the encoding of the next Unicode code poi It is an error when a code unit in the range `0xd800` to `0xdfff` is encountered outside of a valid UTF-16 surrogate pair (this changed in version 2.6.0). +Unicode rules do not rely on other rules. + ###### `any` * Succeeds when the input is not empty, and: @@ -596,7 +880,7 @@ It is an error when a code unit in the range `0xd800` to `0xdfff` is encountered ###### `bom` -* Equivalent to `one< 0xfeff >`. +* [Equivalent] to `one< 0xfeff >`. ###### `not_one< C... >` @@ -628,28 +912,33 @@ It is an error when a code unit in the range `0xd800` to `0xdfff` is encountered ###### `ranges< C1, D1, C2, D2, ... >` -* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ... >`. +* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ... >`. ###### `ranges< C1, D1, C2, D2, ..., E >` -* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`. +* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`. ###### `string< C... >` -* Equivalent to `seq< one< C >... >`. +* [Equivalent] to `seq< one< C >... >`. ### ICU Support The following rules depend on the [International Components for Unicode (ICU)](http://icu-project.org/) that provide the means to match characters with specific Unicode character properties. -Because of the external dependency, the rules are in the contrib-section, and the required header files are not automatically included in `tao/pegtl.hpp`. +Because of the external dependency, the rules are in contrib, and the required header files are not automatically included in `tao/pegtl.hpp`. The ICU-based rules are again available in multiple versions, -* in namespace `tao::pegtl::icu::utf8` for UTF-8 encoded inputs, -* in namespace `tao::pegtl::icu::utf16_be` for big-endian UTF-16 encoded inputs, -* in namespace `tao::pegtl::icu::utf16_le` for little-endian UTF-16 encoded inputs, -* in namespace `tao::pegtl::icu::utf32_be` for big-endian UTF-32 encoded inputs, and -* in namespace `tao::pegtl::icu::utf32_le` for little-endian UTF-32 encoded inputs. +* in namespace `tao::pegtl::utf8::icu` for UTF-8 encoded inputs, +* in namespace `tao::pegtl::utf16_be::icu` for big-endian UTF-16 encoded inputs, +* in namespace `tao::pegtl::utf16_le::icu` for little-endian UTF-16 encoded inputs, +* in namespace `tao::pegtl::utf32_be::icu` for big-endian UTF-32 encoded inputs, and +* in namespace `tao::pegtl::utf32_le::icu` for little-endian UTF-32 encoded inputs. + +And, for convenience, they again appear in multiple namespace aliases, + +* namespace alias `tao::pegtl::utf16::icu` for native-endian UTF-16 encoded inputs, +* namespace alias `tao::pegtl::utf32::icu` for native-endian UTF-32 encoded inputs. To use these rules it is necessary to provide an include path to the ICU library, to link the application against `libicu`, and to manually include one or more of the following header files: @@ -692,199 +981,199 @@ Convenience wrappers for binary properties. ###### `alphabetic` -* Equivalent to `binary_property< UCHAR_ALPHABETIC >`. +* [Equivalent] to `binary_property< UCHAR_ALPHABETIC >`. ###### `ascii_hex_digit` -* Equivalent to `binary_property< UCHAR_ASCII_HEX_DIGIT >`. +* [Equivalent] to `binary_property< UCHAR_ASCII_HEX_DIGIT >`. ###### `bidi_control` -* Equivalent to `binary_property< UCHAR_BIDI_CONTROL >`. +* [Equivalent] to `binary_property< UCHAR_BIDI_CONTROL >`. ###### `bidi_mirrored` -* Equivalent to `binary_property< UCHAR_BIDI_MIRRORED >`. +* [Equivalent] to `binary_property< UCHAR_BIDI_MIRRORED >`. ###### `case_sensitive` -* Equivalent to `binary_property< UCHAR_CASE_SENSITIVE >`. +* [Equivalent] to `binary_property< UCHAR_CASE_SENSITIVE >`. ###### `dash` -* Equivalent to `binary_property< UCHAR_DASH >`. +* [Equivalent] to `binary_property< UCHAR_DASH >`. ###### `default_ignorable_code_point` -* Equivalent to `binary_property< UCHAR_DEFAULT_IGNORABLE_CODE_POINT >`. +* [Equivalent] to `binary_property< UCHAR_DEFAULT_IGNORABLE_CODE_POINT >`. ###### `deprecated` -* Equivalent to `binary_property< UCHAR_DEPRECATED >`. +* [Equivalent] to `binary_property< UCHAR_DEPRECATED >`. ###### `diacritic` -* Equivalent to `binary_property< UCHAR_DIACRITIC >`. +* [Equivalent] to `binary_property< UCHAR_DIACRITIC >`. ###### `extender` -* Equivalent to `binary_property< UCHAR_EXTENDER >`. +* [Equivalent] to `binary_property< UCHAR_EXTENDER >`. ###### `full_composition_exclusion` -* Equivalent to `binary_property< UCHAR_FULL_COMPOSITION_EXCLUSION >`. +* [Equivalent] to `binary_property< UCHAR_FULL_COMPOSITION_EXCLUSION >`. ###### `grapheme_base` -* Equivalent to `binary_property< UCHAR_GRAPHEME_BASE >`. +* [Equivalent] to `binary_property< UCHAR_GRAPHEME_BASE >`. ###### `grapheme_extend` -* Equivalent to `binary_property< UCHAR_GRAPHEME_EXTEND >`. +* [Equivalent] to `binary_property< UCHAR_GRAPHEME_EXTEND >`. ###### `grapheme_link` -* Equivalent to `binary_property< UCHAR_GRAPHEME_LINK >`. +* [Equivalent] to `binary_property< UCHAR_GRAPHEME_LINK >`. ###### `hex_digit` -* Equivalent to `binary_property< UCHAR_HEX_DIGIT >`. +* [Equivalent] to `binary_property< UCHAR_HEX_DIGIT >`. ###### `hyphen` -* Equivalent to `binary_property< UCHAR_HYPHEN >`. +* [Equivalent] to `binary_property< UCHAR_HYPHEN >`. ###### `id_continue` -* Equivalent to `binary_property< UCHAR_ID_CONTINUE >`. +* [Equivalent] to `binary_property< UCHAR_ID_CONTINUE >`. ###### `id_start` -* Equivalent to `binary_property< UCHAR_ID_START >`. +* [Equivalent] to `binary_property< UCHAR_ID_START >`. ###### `ideographic` -* Equivalent to `binary_property< UCHAR_IDEOGRAPHIC >`. +* [Equivalent] to `binary_property< UCHAR_IDEOGRAPHIC >`. ###### `ids_binary_operator` -* Equivalent to `binary_property< UCHAR_IDS_BINARY_OPERATOR >`. +* [Equivalent] to `binary_property< UCHAR_IDS_BINARY_OPERATOR >`. ###### `ids_trinary_operator` -* Equivalent to `binary_property< UCHAR_IDS_TRINARY_OPERATOR >`. +* [Equivalent] to `binary_property< UCHAR_IDS_TRINARY_OPERATOR >`. ###### `join_control` -* Equivalent to `binary_property< UCHAR_JOIN_CONTROL >`. +* [Equivalent] to `binary_property< UCHAR_JOIN_CONTROL >`. ###### `logical_order_exception` -* Equivalent to `binary_property< UCHAR_LOGICAL_ORDER_EXCEPTION >`. +* [Equivalent] to `binary_property< UCHAR_LOGICAL_ORDER_EXCEPTION >`. ###### `lowercase` -* Equivalent to `binary_property< UCHAR_LOWERCASE >`. +* [Equivalent] to `binary_property< UCHAR_LOWERCASE >`. ###### `math` -* Equivalent to `binary_property< UCHAR_MATH >`. +* [Equivalent] to `binary_property< UCHAR_MATH >`. ###### `nfc_inert` -* Equivalent to `binary_property< UCHAR_NFC_INERT >`. +* [Equivalent] to `binary_property< UCHAR_NFC_INERT >`. ###### `nfd_inert` -* Equivalent to `binary_property< UCHAR_NFD_INERT >`. +* [Equivalent] to `binary_property< UCHAR_NFD_INERT >`. ###### `nfkc_inert` -* Equivalent to `binary_property< UCHAR_NFKC_INERT >`. +* [Equivalent] to `binary_property< UCHAR_NFKC_INERT >`. ###### `nfkd_inert` -* Equivalent to `binary_property< UCHAR_NFKD_INERT >`. +* [Equivalent] to `binary_property< UCHAR_NFKD_INERT >`. ###### `noncharacter_code_point` -* Equivalent to `binary_property< UCHAR_NONCHARACTER_CODE_POINT >`. +* [Equivalent] to `binary_property< UCHAR_NONCHARACTER_CODE_POINT >`. ###### `pattern_syntax` -* Equivalent to `binary_property< UCHAR_PATTERN_SYNTAX >`. +* [Equivalent] to `binary_property< UCHAR_PATTERN_SYNTAX >`. ###### `pattern_white_space` -* Equivalent to `binary_property< UCHAR_PATTERN_WHITE_SPACE >`. +* [Equivalent] to `binary_property< UCHAR_PATTERN_WHITE_SPACE >`. ###### `posix_alnum` -* Equivalent to `binary_property< UCHAR_POSIX_ALNUM >`. +* [Equivalent] to `binary_property< UCHAR_POSIX_ALNUM >`. ###### `posix_blank` -* Equivalent to `binary_property< UCHAR_POSIX_BLANK >`. +* [Equivalent] to `binary_property< UCHAR_POSIX_BLANK >`. ###### `posix_graph` -* Equivalent to `binary_property< UCHAR_POSIX_GRAPH >`. +* [Equivalent] to `binary_property< UCHAR_POSIX_GRAPH >`. ###### `posix_print` -* Equivalent to `binary_property< UCHAR_POSIX_PRINT >`. +* [Equivalent] to `binary_property< UCHAR_POSIX_PRINT >`. ###### `posix_xdigit` -* Equivalent to `binary_property< UCHAR_POSIX_XDIGIT >`. +* [Equivalent] to `binary_property< UCHAR_POSIX_XDIGIT >`. ###### `quotation_mark` -* Equivalent to `binary_property< UCHAR_QUOTATION_MARK >`. +* [Equivalent] to `binary_property< UCHAR_QUOTATION_MARK >`. ###### `radical` -* Equivalent to `binary_property< UCHAR_RADICAL >`. +* [Equivalent] to `binary_property< UCHAR_RADICAL >`. ###### `s_term` -* Equivalent to `binary_property< UCHAR_S_TERM >`. +* [Equivalent] to `binary_property< UCHAR_S_TERM >`. ###### `segment_starter` -* Equivalent to `binary_property< UCHAR_SEGMENT_STARTER >`. +* [Equivalent] to `binary_property< UCHAR_SEGMENT_STARTER >`. ###### `soft_dotted` -* Equivalent to `binary_property< UCHAR_SOFT_DOTTED >`. +* [Equivalent] to `binary_property< UCHAR_SOFT_DOTTED >`. ###### `terminal_punctuation` -* Equivalent to `binary_property< UCHAR_TERMINAL_PUNCTUATION >`. +* [Equivalent] to `binary_property< UCHAR_TERMINAL_PUNCTUATION >`. ###### `unified_ideograph` -* Equivalent to `binary_property< UCHAR_UNIFIED_IDEOGRAPH >`. +* [Equivalent] to `binary_property< UCHAR_UNIFIED_IDEOGRAPH >`. ###### `uppercase` -* Equivalent to `binary_property< UCHAR_UPPERCASE >`. +* [Equivalent] to `binary_property< UCHAR_UPPERCASE >`. ###### `variation_selector` -* Equivalent to `binary_property< UCHAR_VARIATION_SELECTOR >`. +* [Equivalent] to `binary_property< UCHAR_VARIATION_SELECTOR >`. ###### `white_space` -* Equivalent to `binary_property< UCHAR_WHITE_SPACE >`. +* [Equivalent] to `binary_property< UCHAR_WHITE_SPACE >`. ###### `xid_continue` -* Equivalent to `binary_property< UCHAR_XID_CONTINUE >`. +* [Equivalent] to `binary_property< UCHAR_XID_CONTINUE >`. ###### `xid_start` -* Equivalent to `binary_property< UCHAR_XID_START >`. +* [Equivalent] to `binary_property< UCHAR_XID_START >`. ### ICU Rules for Enumerated Properties @@ -893,67 +1182,67 @@ Convenience wrappers for enumerated properties. ###### `bidi_class< V >` * `V` is of type `UCharDirection`. -* Equivalent to `property_value< UCHAR_BIDI_CLASS, V >`. +* [Equivalent] to `property_value< UCHAR_BIDI_CLASS, V >`. ###### `block< V >` * `V` is of type `UBlockCode`. -* Equivalent to `property_value< UCHAR_BLOCK, V >`. +* [Equivalent] to `property_value< UCHAR_BLOCK, V >`. ###### `decomposition_type< V >` * `V` is of type `UDecompositionType`. -* Equivalent to `property_value< UCHAR_DECOMPOSITION_TYPE, V >`. +* [Equivalent] to `property_value< UCHAR_DECOMPOSITION_TYPE, V >`. ###### `east_asian_width< V >` * `V` is of type `UEastAsianWidth`. -* Equivalent to `property_value< UCHAR_EAST_ASIAN_WIDTH, V >`. +* [Equivalent] to `property_value< UCHAR_EAST_ASIAN_WIDTH, V >`. ###### `general_category< V >` * `V` is of type `UCharCategory`. -* Equivalent to `property_value< UCHAR_GENERAL_CATEGORY, V >`. +* [Equivalent] to `property_value< UCHAR_GENERAL_CATEGORY, V >`. ###### `grapheme_cluster_break< V >` * `V` is of type `UGraphemeClusterBreak`. -* Equivalent to `property_value< UCHAR_GRAPHEME_CLUSTER_BREAK, V >`. +* [Equivalent] to `property_value< UCHAR_GRAPHEME_CLUSTER_BREAK, V >`. ###### `hangul_syllable_type< V >` * `V` is of type `UHangulSyllableType`. -* Equivalent to `property_value< UCHAR_HANGUL_SYLLABLE_TYPE, V >`. +* [Equivalent] to `property_value< UCHAR_HANGUL_SYLLABLE_TYPE, V >`. ###### `joining_group< V >` * `V` is of type `UJoiningGroup`. -* Equivalent to `property_value< UCHAR_JOINING_GROUP, V >`. +* [Equivalent] to `property_value< UCHAR_JOINING_GROUP, V >`. ###### `joining_type< V >` * `V` is of type `UJoiningType`. -* Equivalent to `property_value< UCHAR_JOINING_TYPE, V >`. +* [Equivalent] to `property_value< UCHAR_JOINING_TYPE, V >`. ###### `line_break< V >` * `V` is of type `ULineBreak`. -* Equivalent to `property_value< UCHAR_LINE_BREAK, V >`. +* [Equivalent] to `property_value< UCHAR_LINE_BREAK, V >`. ###### `numeric_type< V >` * `V` is of type `UNumericType`. -* Equivalent to `property_value< UCHAR_NUMERIC_TYPE, V >`. +* [Equivalent] to `property_value< UCHAR_NUMERIC_TYPE, V >`. ###### `sentence_break< V >` * `V` is of type `USentenceBreak`. -* Equivalent to `property_value< UCHAR_SENTENCE_BREAK, V >`. +* [Equivalent] to `property_value< UCHAR_SENTENCE_BREAK, V >`. ###### `word_break< V >` * `V` is of type `UWordBreakValues`. -* Equivalent to `property_value< UCHAR_WORD_BREAK, V >`. +* [Equivalent] to `property_value< UCHAR_WORD_BREAK, V >`. ### ICU Rules for Value Properties @@ -962,17 +1251,17 @@ Convenience wrappers for enumerated properties that return a value instead of an ###### `canonical_combining_class< V >` * `V` is of type `std::uint8_t`. -* Equivalent to `property_value< UCHAR_CANONICAL_COMBINING_CLASS, V >`. +* [Equivalent] to `property_value< UCHAR_CANONICAL_COMBINING_CLASS, V >`. ###### `lead_canonical_combining_class< V >` * `V` is of type `std::uint8_t`. -* Equivalent to `property_value< UCHAR_LEAD_CANONICAL_COMBINING_CLASS, V >`. +* [Equivalent] to `property_value< UCHAR_LEAD_CANONICAL_COMBINING_CLASS, V >`. ###### `trail_canonical_combining_class< V >` * `V` is of type `std::uint8_t`. -* Equivalent to `property_value< UCHAR_TRAIL_CANONICAL_COMBINING_CLASS, V >`. +* [Equivalent] to `property_value< UCHAR_TRAIL_CANONICAL_COMBINING_CLASS, V >`. ## Binary Rules @@ -986,11 +1275,15 @@ These rules are available in multiple versions, * in namespace `tao::pegtl::uint64_be` for big-endian 64-bit integer values, and * in namespace `tao::pegtl::uint64_le` for little-endian 64-bit integer values. -These rules read one or more bytes from the input to form (and match) an 8, 16, 32 or 64-bit value, respectively, and template parameters are given as matching `std::uint8_t`, `std::uint16_t`, `std::uint32_t` or `std::uin64_t`. +The binary rules need to be manually included from their corresponding headers in the `contrib` section. -In the following descriptions the parameter N is the size of a single value in bytes, i.e. either 1, 2, 4 or 8. +These rules read one or more bytes from the input to form (and match) an 8, 16, 32 or 64-bit value, respectively, and corresponding template parameters are given as either `std::uint8_t`, `std::uint16_t`, `std::uint32_t` or `std::uin64_t`. + +In the following descriptions, the parameter N is the size of a single value in bytes, i.e. either 1, 2, 4 or 8. The term *input value* indicates a correspondingly sized integer value read from successive bytes of the input. +Binary rules do not rely on other rules. + ###### `any` * Succeeds when the input contains at least N bytes. @@ -1022,15 +1315,15 @@ The term *input value* indicates a correspondingly sized integer value read from ###### `mask_ranges< M, C1, D1, C2, D2, ... >` -* Equivalent to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ... >`. +* [Equivalent] to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ... >`. ###### `mask_ranges< M, C1, D1, C2, D2, ..., E >` -* Equivalent to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ..., mask_one< M, E > >`. +* [Equivalent] to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ..., mask_one< M, E > >`. ###### `mask_string< M, C... >` -* Equivalent to `seq< mask_one< M, C >... >`. +* [Equivalent] to `seq< mask_one< M, C >... >`. ###### `not_one< C... >` @@ -1058,15 +1351,15 @@ The term *input value* indicates a correspondingly sized integer value read from ###### `ranges< C1, D1, C2, D2, ... >` -* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ... >`. +* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ... >`. ###### `ranges< C1, D1, C2, D2, ..., E >` -* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`. +* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`. ###### `string< C... >` -* Equivalent to `seq< one< C >... >`. +* [Equivalent] to `seq< one< C >... >`. ## Full Index @@ -1106,8 +1399,8 @@ The term *input value* indicates a correspondingly sized integer value read from * [`east_asian_width< V >`](#east_asian_width-v-) <sup>[(icu rules)](#icu-rules-for-enumerated-properties)</sup> * [`enable< R... >`](#enable-r-) <sup>[(meta-rules)](#meta-rules)</sup> * [`eof`](#eof) <sup>[(atomic rules)](#atomic-rules)</sup> -* [`eol`](#eol) <sup>[(ascii rules)](#ascii-rules)</sup> -* [`eolf`](#eolf) <sup>[(ascii rules)](#ascii-rules)</sup> +* [`eol`](#eol) <sup>[(atomic rules)](#atomic-rules)</sup> +* [`eolf`](#eolf) <sup>[(atomic rules)](#atomic-rules)</sup> * [`extender`](#extender) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup> * [`failure`](#failure) <sup>[(atomic rules)](#atomic-rules)</sup> * [`forty_two< C... >`](#forty_two-c-) <sup>[(ascii rules)](#ascii-rules)</sup> @@ -1245,4 +1538,8 @@ The term *input value* indicates a correspondingly sized integer value read from * [`xid_continue`](#xid_continue) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup> * [`xid_start`](#xid_start) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup> -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey + +[Equivalent]: #equivalence +[implementation]: #implementation +[Meta data]: Meta-Data-and-Visit.md diff --git a/packages/PEGTL/doc/Rules-and-Grammars.md b/packages/PEGTL/doc/Rules-and-Grammars.md index f577ad97d990a013adcb9273f3febca03959529a..0fd0caa4c0a206832cc5baa886629277f686dec2 100644 --- a/packages/PEGTL/doc/Rules-and-Grammars.md +++ b/packages/PEGTL/doc/Rules-and-Grammars.md @@ -136,8 +136,8 @@ Rules with the simplified interface are called without the states as arguments. ```c++ struct simple_rule { - template< typename Input > - static bool match( Input& in ) { ... } + template< typename ParseInput > + static bool match( ParseInput& in ) { ... } }; ``` @@ -162,8 +162,8 @@ namespace modulus static_assert( M > 1, "Modulus must be greater than 1" ); static_assert( R < M, "Remainder must be less than modulus" ); - template< typename Input > - static bool match( Input& in ) + template< typename ParseInput > + static bool match( ParseInput& in ) { if( ! in.empty() ) { if( ( ( *in.begin() ) % M ) == R ) { @@ -200,16 +200,16 @@ The signature of `match()` in a complex rule takes the following form. ```c++ struct complex_rule { - // Optional; explained in the section on Grammar Analysis: - using analyze_t = ...; + using rule_t = complex_rule; + using subs_t = tao::pegtl::empty_list; // Or tao::pegtl::rule_list< sub_rules_of_complex_rule... >. template< tao::pegtl::apply_mode A, tao::pegtl::rewind_mode M, template< typename... > class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& in, States&&... ) + static bool match( ParseInput& in, States&&... ) { ... } }; ``` @@ -238,9 +238,9 @@ struct seq rewind_mode M, template< typename... > class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& in, States&&... st ) + static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< M >(); using m_t = decltype( m ); @@ -286,8 +286,8 @@ The action stores the matched string that corresponds to `"foo"` in a string var template<> struct action< long_literal_id > { - template< typename Input > - static void apply( const Input& in, + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& id, const std::string& ) { @@ -320,8 +320,8 @@ The custom rule itself tao::pegtl::rewind_mode M, template< typename... > class Action, template< typename... > class Control, - typename Input > - static bool match( Input& in, + typename ParseInput > + static bool match( ParseInput& in, const std::string& id, const std::string& ) { @@ -351,8 +351,8 @@ In this case the rule `long_literal_body` is redundant, however real-world examp template<> struct action< long_literal_body > { - template< typename Input > - static void apply( const Input& in, + template< typename ActionInput > + static void apply( const ActionInput& in, const std::string&, std::string& body ) { @@ -394,4 +394,4 @@ long literal id was: "fraggle" long literal body was: "[foo[" ``` -Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/doc/Thank-You.md b/packages/PEGTL/doc/Thank-You.md deleted file mode 100644 index 63beb187c8e0e95720d965e3a6e7f14ff5ef04d8..0000000000000000000000000000000000000000 --- a/packages/PEGTL/doc/Thank-You.md +++ /dev/null @@ -1,41 +0,0 @@ -# Thank You - -In appreciation of all contributions here are the people that have [directly contributed](https://github.com/taocpp/PEGTL/graphs/contributors) to the PEGTL and/or its development. - -[<img alt="andoma" src="https://avatars2.githubusercontent.com/u/216384?v=4&s=117" width="117">](https://github.com/andoma) -[<img alt="Bjoe" src="https://avatars3.githubusercontent.com/u/727911?v=4&s=117" width="117">](https://github.com/Bjoe) -[<img alt="bwagner" src="https://avatars3.githubusercontent.com/u/447049?v=4&s=117" width="117">](https://github.com/bwagner) -[<img alt="cdiggins" src="https://avatars2.githubusercontent.com/u/1759994?s=460&v=4?v=4&s=117" width="117">](https://github.com/cdiggins) -[<img alt="delpinux" src="https://avatars0.githubusercontent.com/u/35096584?v=4&s=117" width="117">](https://github.com/delpinux) -[<img alt="dkopecek" src="https://avatars2.githubusercontent.com/u/1353140?v=4&s=117" width="117">](https://github.com/dkopecek) -[<img alt="irrequietus" src="https://avatars0.githubusercontent.com/u/231192?v=4&s=117" width="117">](https://github.com/irrequietus) -[<img alt="jedelbo" src="https://avatars2.githubusercontent.com/u/572755?v=4&s=117" width="117">](https://github.com/jedelbo) -[<img alt="joelfrederico" src="https://avatars0.githubusercontent.com/u/458871?v=4&s=117" width="117">](https://github.com/joelfrederico) -[<img alt="jovermann" src="https://avatars3.githubusercontent.com/u/6087443?v=4&s=117" width="117">](https://github.com/jovermann) -[<img alt="kneth" src="https://avatars0.githubusercontent.com/u/1225363?v=4&s=117" width="117">](https://github.com/kneth) -[<img alt="kuzmas" src="https://avatars1.githubusercontent.com/u/1858553?v=4&s=117" width="117">](https://github.com/kuzmas) -[<img alt="lambdafu" src="https://avatars1.githubusercontent.com/u/1138455?v=4&s=117" width="117">](https://github.com/lambdafu) -[<img alt="lichray" src="https://avatars2.githubusercontent.com/u/433009?v=4&s=117" width="117">](https://github.com/lichray) -[<img alt="michael-brade" src="https://avatars0.githubusercontent.com/u/8768950?v=4&s=117" width="117">](https://github.com/michael-brade) -[<img alt="mkrupcale" src="https://avatars1.githubusercontent.com/u/13936020?v=4&s=117" width="117">](https://github.com/mkrupcale) -[<img alt="NewProggie" src="https://avatars3.githubusercontent.com/u/162319?s=460&v=4?v=4&s=117" width="117">](https://github.com/NewProggie) -[<img alt="pauloscustodio" src="https://avatars1.githubusercontent.com/u/70773?v=4&s=117" width="117">](https://github.com/pauloscustodio) -[<img alt="pleroux0" src="https://avatars2.githubusercontent.com/u/39619854?v=4&s=117" width="117">](https://github.com/pleroux0) -[<img alt="quadfault" src="https://avatars3.githubusercontent.com/u/30195320?v=4&s=117" width="117">](https://github.com/quadfault) -[<img alt="samhocevar" src="https://avatars2.githubusercontent.com/u/245089?v=4&s=117" width="117">](https://github.com/samhocevar) -[<img alt="sanssecours" src="https://avatars2.githubusercontent.com/u/691989?v=4&s=117" width="117">](https://github.com/sanssecours) -[<img alt="sgbeal" src="https://avatars1.githubusercontent.com/u/235303?v=4&s=117" width="117">](https://github.com/sgbeal) -[<img alt="studoot" src="https://avatars1.githubusercontent.com/u/799344?v=4&s=117" width="117">](https://github.com/studoot) -[<img alt="SvenJo" src="https://avatars1.githubusercontent.com/u/1538181?s=460&v=4?v=4&s=117" width="117">](https://github.com/SvenJo) -[<img alt="wickedmic" src="https://avatars1.githubusercontent.com/u/12001183?v=4&s=117" width="117">](https://github.com/wickedmic) -[<img alt="zhihaoy" src="https://avatars2.githubusercontent.com/u/43971430?v=4&s=117" width="117">](https://github.com/zhihaoy) - -## The Art of C++ - -Members of the *Art of C++* project. - -[<img alt="ColinH" src="https://avatars0.githubusercontent.com/u/113184?v=4&s=117" width="117">](https://github.com/ColinH) -[<img alt="d-frey" src="https://avatars2.githubusercontent.com/u/3956325?v=4&s=117" width="117">](https://github.com/d-frey) -[<img alt="uilianries" src="https://avatars0.githubusercontent.com/u/4870173?v=4&s=117" width="117">](https://github.com/uilianries) - -Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey diff --git a/packages/PEGTL/include/tao/pegtl.hpp b/packages/PEGTL/include/tao/pegtl.hpp index 42141a9df128515b3638fca8b70baf585c876d62..9ef19286fdc5f4663f284e70ee9c70a91133fe33 100644 --- a/packages/PEGTL/include/tao/pegtl.hpp +++ b/packages/PEGTL/include/tao/pegtl.hpp @@ -1,33 +1,29 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_HPP #define TAO_PEGTL_HPP #include "pegtl/config.hpp" -#include "pegtl/version.hpp" - #include "pegtl/parse.hpp" +#include "pegtl/version.hpp" #include "pegtl/ascii.hpp" #include "pegtl/rules.hpp" -#include "pegtl/uint16.hpp" -#include "pegtl/uint32.hpp" -#include "pegtl/uint64.hpp" -#include "pegtl/uint8.hpp" -#include "pegtl/utf16.hpp" -#include "pegtl/utf32.hpp" #include "pegtl/utf8.hpp" #include "pegtl/argv_input.hpp" #include "pegtl/buffer_input.hpp" #include "pegtl/cstream_input.hpp" -#include "pegtl/file_input.hpp" #include "pegtl/istream_input.hpp" #include "pegtl/memory_input.hpp" #include "pegtl/read_input.hpp" #include "pegtl/string_input.hpp" +// This has to be included *after* the above inputs, +// otherwise the amalgamated header will not work! +#include "pegtl/file_input.hpp" + #include "pegtl/change_action.hpp" #include "pegtl/change_action_and_state.hpp" #include "pegtl/change_action_and_states.hpp" @@ -42,9 +38,7 @@ #include "pegtl/discard_input_on_failure.hpp" #include "pegtl/discard_input_on_success.hpp" -// The following are not included by -// default because they include <iostream>. - -// #include "pegtl/analyze.hpp" +#include "pegtl/must_if.hpp" +#include "pegtl/visit.hpp" #endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/analyze_cycles.hpp b/packages/PEGTL/include/tao/pegtl/analysis/analyze_cycles.hpp deleted file mode 100644 index 9f7ce5f83b130b1a548f1f098c8c3f7a1b702e44..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/analyze_cycles.hpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_ANALYZE_CYCLES_HPP -#define TAO_PEGTL_ANALYSIS_ANALYZE_CYCLES_HPP - -#include <cassert> - -#include <map> -#include <set> -#include <stdexcept> - -#include <iostream> -#include <utility> - -#include "../config.hpp" - -#include "grammar_info.hpp" -#include "insert_guard.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - class analyze_cycles_impl - { - protected: - explicit analyze_cycles_impl( const bool verbose ) noexcept - : m_verbose( verbose ), - m_problems( 0 ) - { - } - - const bool m_verbose; - unsigned m_problems; - grammar_info m_info; - std::set< std::string > m_stack; - std::map< std::string, bool > m_cache; - std::map< std::string, bool > m_results; - - [[nodiscard]] std::map< std::string, rule_info >::const_iterator find( const std::string& name ) const noexcept - { - const auto iter = m_info.map.find( name ); - assert( iter != m_info.map.end() ); - return iter; - } - - [[nodiscard]] bool work( const std::map< std::string, rule_info >::const_iterator& start, const bool accum ) - { - const auto j = m_cache.find( start->first ); - - if( j != m_cache.end() ) { - return j->second; - } - if( const auto g = insert_guard( m_stack, start->first ) ) { - switch( start->second.type ) { - case rule_type::any: { - bool a = false; - for( const auto& r : start->second.rules ) { - a = a || work( find( r ), accum || a ); - } - return m_cache[ start->first ] = true; - } - case rule_type::opt: { - bool a = false; - for( const auto& r : start->second.rules ) { - a = a || work( find( r ), accum || a ); - } - return m_cache[ start->first ] = false; - } - case rule_type::seq: { - bool a = false; - for( const auto& r : start->second.rules ) { - a = a || work( find( r ), accum || a ); - } - return m_cache[ start->first ] = a; - } - case rule_type::sor: { - bool a = true; - for( const auto& r : start->second.rules ) { - a = a && work( find( r ), accum ); - } - return m_cache[ start->first ] = a; - } - } - throw std::logic_error( "code should be unreachable: invalid rule_type value" ); // NOLINT, LCOV_EXCL_LINE - } - if( !accum ) { - ++m_problems; - if( m_verbose ) { - std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl; // LCOV_EXCL_LINE - } - } - return m_cache[ start->first ] = accum; - } - }; - - template< typename Grammar > - class analyze_cycles - : private analyze_cycles_impl - { - public: - explicit analyze_cycles( const bool verbose ) - : analyze_cycles_impl( verbose ) - { - Grammar::analyze_t::template insert< Grammar >( m_info ); - } - - [[nodiscard]] std::size_t problems() - { - for( auto i = m_info.map.begin(); i != m_info.map.end(); ++i ) { - m_results[ i->first ] = work( i, false ); - m_cache.clear(); - } - return m_problems; - } - - template< typename Rule > - [[nodiscard]] bool consumes() const noexcept - { - const auto i = m_results.find( internal::demangle< Rule >() ); - assert( i != m_results.end() ); - return i->second; - } - }; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/counted.hpp b/packages/PEGTL/include/tao/pegtl/analysis/counted.hpp deleted file mode 100644 index 2c1939ca1dc88282d178f373c0243fa89696c0a5..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/counted.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_COUNTED_HPP -#define TAO_PEGTL_ANALYSIS_COUNTED_HPP - -#include "../config.hpp" - -#include "generic.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - template< rule_type Type, unsigned Count, typename... Rules > - struct counted - : generic< ( Count != 0 ) ? Type : rule_type::opt, Rules... > - { - }; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/generic.hpp b/packages/PEGTL/include/tao/pegtl/analysis/generic.hpp deleted file mode 100644 index ae8685ab84b3915a1e8cf3c39666b2138ea7a8df..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/generic.hpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_GENERIC_HPP -#define TAO_PEGTL_ANALYSIS_GENERIC_HPP - -#include "../config.hpp" - -#include "grammar_info.hpp" -#include "insert_rules.hpp" -#include "rule_type.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - template< rule_type Type, typename... Rules > - struct generic - { - template< typename Name > - static std::string insert( grammar_info& g ) - { - const auto [ it, success ] = g.insert< Name >( Type ); - if( success ) { - insert_rules< Rules... >::insert( g, it->second ); - } - return it->first; - } - }; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/grammar_info.hpp b/packages/PEGTL/include/tao/pegtl/analysis/grammar_info.hpp deleted file mode 100644 index a6f63ed68189dc60b69df12e7e415195a7ca0fdb..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/grammar_info.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_GRAMMAR_INFO_HPP -#define TAO_PEGTL_ANALYSIS_GRAMMAR_INFO_HPP - -#include <map> -#include <string> -#include <utility> - -#include "../config.hpp" -#include "../internal/demangle.hpp" - -#include "rule_info.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - struct grammar_info - { - using map_t = std::map< std::string, rule_info >; - map_t map; - - template< typename Name > - auto insert( const rule_type type ) - { - return map.emplace( internal::demangle< Name >(), rule_info( type ) ); - } - }; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/insert_guard.hpp b/packages/PEGTL/include/tao/pegtl/analysis/insert_guard.hpp deleted file mode 100644 index 1fb00503cf8895945df35b2766482c470149b0a6..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/insert_guard.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_INSERT_GUARD_HPP -#define TAO_PEGTL_ANALYSIS_INSERT_GUARD_HPP - -#include <utility> - -#include "../config.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - template< typename C > - class insert_guard - { - public: - insert_guard( C& container, const typename C::value_type& value ) - : m_i( container.insert( value ) ), - m_c( container ) - { - } - - insert_guard( const insert_guard& ) = delete; - insert_guard( insert_guard&& ) = delete; - - ~insert_guard() - { - if( m_i.second ) { - m_c.erase( m_i.first ); - } - } - - void operator=( const insert_guard& ) = delete; - void operator=( insert_guard&& ) = delete; - - explicit operator bool() const noexcept - { - return m_i.second; - } - - private: - const std::pair< typename C::iterator, bool > m_i; - C& m_c; - }; - - template< typename C > - insert_guard( C&, const typename C::value_type& )->insert_guard< C >; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/insert_rules.hpp b/packages/PEGTL/include/tao/pegtl/analysis/insert_rules.hpp deleted file mode 100644 index 617031a63c3ef86aec1456c4376c720e811ed5b1..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/insert_rules.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_INSERT_RULES_HPP -#define TAO_PEGTL_ANALYSIS_INSERT_RULES_HPP - -#include "../config.hpp" - -#include "grammar_info.hpp" -#include "rule_info.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - template< typename... Rules > - struct insert_rules - { - static void insert( grammar_info& g, rule_info& r ) - { - ( r.rules.emplace_back( Rules::analyze_t::template insert< Rules >( g ) ), ... ); - } - }; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/rule_info.hpp b/packages/PEGTL/include/tao/pegtl/analysis/rule_info.hpp deleted file mode 100644 index 0f06950bdc88f8a7333e9585137fa5aa721a0870..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/rule_info.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_RULE_INFO_HPP -#define TAO_PEGTL_ANALYSIS_RULE_INFO_HPP - -#include <string> -#include <vector> - -#include "../config.hpp" - -#include "rule_type.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - struct rule_info - { - explicit rule_info( const rule_type in_type ) noexcept - : type( in_type ) - { - } - - rule_type type; - std::vector< std::string > rules; - }; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analysis/rule_type.hpp b/packages/PEGTL/include/tao/pegtl/analysis/rule_type.hpp deleted file mode 100644 index ec1f29c91558ba2e0dfebd001569ae4b04103bad..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analysis/rule_type.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYSIS_RULE_TYPE_HPP -#define TAO_PEGTL_ANALYSIS_RULE_TYPE_HPP - -#include "../config.hpp" - -namespace TAO_PEGTL_NAMESPACE::analysis -{ - enum class rule_type : char - { - any, // Consumption-on-success is always true; assumes bounded repetition of conjunction of sub-rules. - opt, // Consumption-on-success not necessarily true; assumes bounded repetition of conjunction of sub-rules. - seq, // Consumption-on-success depends on consumption of (non-zero bounded repetition of) conjunction of sub-rules. - sor // Consumption-on-success depends on consumption of (non-zero bounded repetition of) disjunction of sub-rules. - }; - -} // namespace TAO_PEGTL_NAMESPACE::analysis - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/analyze.hpp b/packages/PEGTL/include/tao/pegtl/analyze.hpp deleted file mode 100644 index d0e0641ce2ea8071cb52812a55c99240d50ff640..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/analyze.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_ANALYZE_HPP -#define TAO_PEGTL_ANALYZE_HPP - -#include "config.hpp" - -#include "analysis/analyze_cycles.hpp" - -namespace TAO_PEGTL_NAMESPACE -{ - template< typename Rule > - [[nodiscard]] std::size_t analyze( const bool verbose = true ) - { - return analysis::analyze_cycles< Rule >( verbose ).problems(); - } - -} // namespace TAO_PEGTL_NAMESPACE - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/apply_mode.hpp b/packages/PEGTL/include/tao/pegtl/apply_mode.hpp index 144f0cb79426edf60d11f7b7f1ffa89834b431c4..962d4f00def6c26d40dc93af2a38f1bf90796578 100644 --- a/packages/PEGTL/include/tao/pegtl/apply_mode.hpp +++ b/packages/PEGTL/include/tao/pegtl/apply_mode.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_APPLY_MODE_HPP diff --git a/packages/PEGTL/include/tao/pegtl/argv_input.hpp b/packages/PEGTL/include/tao/pegtl/argv_input.hpp index c7b1430d02086f3d0f1cb76ba3e72ecbef246f4c..741a3574ddf2ab2de83afd677237f19382826512 100644 --- a/packages/PEGTL/include/tao/pegtl/argv_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/argv_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_ARGV_INPUT_HPP @@ -29,18 +29,16 @@ namespace TAO_PEGTL_NAMESPACE template< tracking_mode P = tracking_mode::eager, typename Eol = eol::lf_crlf > struct argv_input - : public memory_input< P, Eol > + : memory_input< P, Eol > { template< typename T > - argv_input( char** argv, const std::size_t argn, T&& in_source ) // NOLINT + argv_input( char** argv, const std::size_t argn, T&& in_source ) : memory_input< P, Eol >( static_cast< const char* >( argv[ argn ] ), std::forward< T >( in_source ) ) - { - } + {} - argv_input( char** argv, const std::size_t argn ) // NOLINT + argv_input( char** argv, const std::size_t argn ) : argv_input( argv, argn, internal::make_argv_source( argn ) ) - { - } + {} }; template< typename... Ts > diff --git a/packages/PEGTL/include/tao/pegtl/ascii.hpp b/packages/PEGTL/include/tao/pegtl/ascii.hpp index b28cc350a364d1863c5b261b73d70a3a5a264fbd..1e4f1032f4287f4aac2c711c5659086c7666ad1d 100644 --- a/packages/PEGTL/include/tao/pegtl/ascii.hpp +++ b/packages/PEGTL/include/tao/pegtl/ascii.hpp @@ -1,13 +1,12 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_ASCII_HPP #define TAO_PEGTL_ASCII_HPP #include "config.hpp" -#include "eol.hpp" -#include "internal/always_false.hpp" +#include "internal/dependent_false.hpp" #include "internal/result_on_found.hpp" #include "internal/rules.hpp" @@ -22,13 +21,12 @@ namespace TAO_PEGTL_NAMESPACE struct blank : internal::one< internal::result_on_found::success, internal::peek_char, ' ', '\t' > {}; struct digit : internal::range< internal::result_on_found::success, internal::peek_char, '0', '9' > {}; struct ellipsis : internal::string< '.', '.', '.' > {}; - struct eolf : internal::eolf {}; template< char... Cs > struct forty_two : internal::rep< 42, internal::one< internal::result_on_found::success, internal::peek_char, Cs... > > {}; struct identifier_first : internal::identifier_first {}; struct identifier_other : internal::identifier_other {}; struct identifier : internal::identifier {}; template< char... Cs > struct istring : internal::istring< Cs... > {}; - template< char... Cs > struct keyword : internal::seq< internal::string< Cs... >, internal::not_at< internal::identifier_other > > {}; + template< char... Cs > struct keyword : internal::seq< internal::string< Cs... >, internal::not_at< internal::identifier_other > > { static_assert( sizeof...( Cs ) > 0 ); }; struct lower : internal::range< internal::result_on_found::success, internal::peek_char, 'a', 'z' > {}; template< char... Cs > struct not_one : internal::one< internal::result_on_found::failure, internal::peek_char, Cs... > {}; template< char Lo, char Hi > struct not_range : internal::range< internal::result_on_found::failure, internal::peek_char, Lo, Hi > {}; @@ -38,7 +36,7 @@ namespace TAO_PEGTL_NAMESPACE template< char Lo, char Hi > struct range : internal::range< internal::result_on_found::success, internal::peek_char, Lo, Hi > {}; template< char... Cs > struct ranges : internal::ranges< internal::peek_char, Cs... > {}; struct seven : internal::range< internal::result_on_found::success, internal::peek_char, char( 0 ), char( 127 ) > {}; - struct shebang : internal::if_must< false, internal::string< '#', '!' >, internal::until< internal::eolf > > {}; + struct shebang : internal::seq< internal::string< '#', '!' >, internal::until< internal::eolf > > {}; struct space : internal::one< internal::result_on_found::success, internal::peek_char, ' ', '\n', '\r', '\t', '\v', '\f' > {}; template< char... Cs > struct string : internal::string< Cs... > {}; template< char C > struct three : internal::string< C, C, C > {}; @@ -47,17 +45,6 @@ namespace TAO_PEGTL_NAMESPACE struct xdigit : internal::ranges< internal::peek_char, '0', '9', 'a', 'f', 'A', 'F' > {}; // clang-format on - template<> - struct keyword<> - { - template< typename Input > - [[nodiscard]] static bool match( Input& /*unused*/ ) noexcept - { - static_assert( internal::always_false< Input >::value, "empty keywords not allowed" ); - return false; - } - }; - } // namespace ascii } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/include/tao/pegtl/buffer_input.hpp b/packages/PEGTL/include/tao/pegtl/buffer_input.hpp index 0487b48ec90344bbc233a0391c33f0236be8ec30..f964787769d7f9ae5146ee3a29d99293ca1c556b 100644 --- a/packages/PEGTL/include/tao/pegtl/buffer_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/buffer_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_BUFFER_INPUT_HPP @@ -201,7 +201,7 @@ namespace TAO_PEGTL_NAMESPACE private: Reader m_reader; std::size_t m_maximum; - std::unique_ptr< char[] > m_buffer; // NOLINT + std::unique_ptr< char[] > m_buffer; iterator_t m_current; char* m_end; const Source m_source; diff --git a/packages/PEGTL/include/tao/pegtl/change_action.hpp b/packages/PEGTL/include/tao/pegtl/change_action.hpp index bd73db8520935d9fa1cae3e352831fc243b00e38..e7ae6d96a8398e1b780bf659bffb31728ef594f9 100644 --- a/packages/PEGTL/include/tao/pegtl/change_action.hpp +++ b/packages/PEGTL/include/tao/pegtl/change_action.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CHANGE_ACTION_HPP @@ -24,9 +24,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" ); return Control< Rule >::template match< A, M, NewAction, Control >( in, st... ); diff --git a/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp b/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp index 84a174f17512ce7bbd8e3437eec29ed4c229fabf..953e3a4bde64cc0476b02218b99484569b44069b 100644 --- a/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp +++ b/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CHANGE_ACTION_AND_STATE_HPP @@ -25,24 +25,24 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" ); - NewState s( static_cast< const Input& >( in ), st... ); + NewState s( static_cast< const ParseInput& >( in ), st... ); if( Control< Rule >::template match< A, M, NewAction, Control >( in, s ) ) { if constexpr( A == apply_mode::action ) { - Action< Rule >::success( static_cast< const Input& >( in ), s, st... ); + Action< Rule >::success( static_cast< const ParseInput& >( in ), s, st... ); } return true; } return false; } - template< typename Input, + template< typename ParseInput, typename... States > - static void success( const Input& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) ) + static void success( const ParseInput& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) ) { s.success( in, st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp b/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp index c4fd02eeeafbfc022d499eddbaab42a26fae2cbe..91ec5bcf8915342fbed441787845a480c7004115 100644 --- a/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp +++ b/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CHANGE_ACTION_AND_STATES_HPP @@ -27,14 +27,14 @@ namespace TAO_PEGTL_NAMESPACE template< typename... > class Control, std::size_t... Ns, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( std::index_sequence< Ns... >, Input& in, States&&... st ) + [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, ParseInput& in, States&&... st ) { auto t = std::tie( st... ); if( Control< Rule >::template match< A, M, NewAction, Control >( in, std::get< Ns >( t )... ) ) { if constexpr( A == apply_mode::action ) { - Action< Rule >::success( static_cast< const Input& >( in ), st... ); + Action< Rule >::success( static_cast< const ParseInput& >( in ), st... ); } return true; } @@ -48,9 +48,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" ); return match< Rule, A, M, Action, Control >( std::index_sequence_for< NewStates... >(), in, NewStates()..., st... ); diff --git a/packages/PEGTL/include/tao/pegtl/change_control.hpp b/packages/PEGTL/include/tao/pegtl/change_control.hpp index cef670118868775f807b2c74806f8e5a190419a2..0440e723df9292a529d47c7714e68ea31a40cff7 100644 --- a/packages/PEGTL/include/tao/pegtl/change_control.hpp +++ b/packages/PEGTL/include/tao/pegtl/change_control.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CHANGE_CONTROL_HPP @@ -23,9 +23,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, NewControl >( in, st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/change_state.hpp b/packages/PEGTL/include/tao/pegtl/change_state.hpp index 9e3568e94d8a3e5cd0653e87be0f26a241e7c544..c433dd8a936948b704b991cf50636e0603cf70b8 100644 --- a/packages/PEGTL/include/tao/pegtl/change_state.hpp +++ b/packages/PEGTL/include/tao/pegtl/change_state.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CHANGE_STATE_HPP @@ -23,23 +23,23 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - NewState s( static_cast< const Input& >( in ), st... ); + NewState s( static_cast< const ParseInput& >( in ), st... ); if( TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, s ) ) { if constexpr( A == apply_mode::action ) { - Action< Rule >::success( static_cast< const Input& >( in ), s, st... ); + Action< Rule >::success( static_cast< const ParseInput& >( in ), s, st... ); } return true; } return false; } - template< typename Input, + template< typename ParseInput, typename... States > - static void success( const Input& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) ) + static void success( const ParseInput& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) ) { s.success( in, st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/change_states.hpp b/packages/PEGTL/include/tao/pegtl/change_states.hpp index 09d49dd10c359f108458fa4d976aa533acd2fb76..bc7ac78d0de92c2c8ecde6da7cbd9d5f9e2107c4 100644 --- a/packages/PEGTL/include/tao/pegtl/change_states.hpp +++ b/packages/PEGTL/include/tao/pegtl/change_states.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CHANGE_STATES_HPP @@ -27,14 +27,14 @@ namespace TAO_PEGTL_NAMESPACE template< typename... > class Control, std::size_t... Ns, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( std::index_sequence< Ns... >, Input& in, States&&... st ) + [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, ParseInput& in, States&&... st ) { auto t = std::tie( st... ); if( TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, std::get< Ns >( t )... ) ) { if constexpr( A == apply_mode::action ) { - Action< Rule >::success( static_cast< const Input& >( in ), st... ); + Action< Rule >::success( static_cast< const ParseInput& >( in ), st... ); } return true; } @@ -48,9 +48,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { return match< Rule, A, M, Action, Control >( std::index_sequence_for< NewStates... >(), in, NewStates()..., st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/config.hpp b/packages/PEGTL/include/tao/pegtl/config.hpp index 4bcdd10353d9d0ffbe3e97059a0fd07b03e8e538..2a67638820588cd04a30f54fefdf19bf66a4bd59 100644 --- a/packages/PEGTL/include/tao/pegtl/config.hpp +++ b/packages/PEGTL/include/tao/pegtl/config.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONFIG_HPP @@ -8,8 +8,4 @@ #define TAO_PEGTL_NAMESPACE tao::pegtl #endif -// Enable some improvements to the readability of -// demangled type names under some circumstances. -// #define TAO_PEGTL_PRETTY_DEMANGLE - #endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/abnf.hpp b/packages/PEGTL/include/tao/pegtl/contrib/abnf.hpp index f90d6b9497142691695fb4227a7665d7256ce3ea..618c68c6136a875f7947d8d62876bb6526ab66e2 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/abnf.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/abnf.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_ABNF_HPP diff --git a/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp b/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp index e1d3292d562b6358d40d9549bb56ca00357c4d10..91747dd90a37d0b9cf402c8992bd3d6d8b5efeff 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_ALPHABET_HPP @@ -35,32 +35,32 @@ namespace TAO_PEGTL_NAMESPACE::alphabet static const int y = 'y'; static const int z = 'z'; - static const int A = 'A'; - static const int B = 'B'; - static const int C = 'C'; - static const int D = 'D'; - static const int E = 'E'; - static const int F = 'F'; - static const int G = 'G'; - static const int H = 'H'; - static const int I = 'I'; - static const int J = 'J'; - static const int K = 'K'; - static const int L = 'L'; - static const int M = 'M'; - static const int N = 'N'; - static const int O = 'O'; - static const int P = 'P'; - static const int Q = 'Q'; - static const int R = 'R'; - static const int S = 'S'; - static const int T = 'T'; - static const int U = 'U'; - static const int V = 'V'; - static const int W = 'W'; - static const int X = 'X'; - static const int Y = 'Y'; - static const int Z = 'Z'; + static const int A = 'A'; // NOLINT(readability-identifier-naming) + static const int B = 'B'; // NOLINT(readability-identifier-naming) + static const int C = 'C'; // NOLINT(readability-identifier-naming) + static const int D = 'D'; // NOLINT(readability-identifier-naming) + static const int E = 'E'; // NOLINT(readability-identifier-naming) + static const int F = 'F'; // NOLINT(readability-identifier-naming) + static const int G = 'G'; // NOLINT(readability-identifier-naming) + static const int H = 'H'; // NOLINT(readability-identifier-naming) + static const int I = 'I'; // NOLINT(readability-identifier-naming) + static const int J = 'J'; // NOLINT(readability-identifier-naming) + static const int K = 'K'; // NOLINT(readability-identifier-naming) + static const int L = 'L'; // NOLINT(readability-identifier-naming) + static const int M = 'M'; // NOLINT(readability-identifier-naming) + static const int N = 'N'; // NOLINT(readability-identifier-naming) + static const int O = 'O'; // NOLINT(readability-identifier-naming) + static const int P = 'P'; // NOLINT(readability-identifier-naming) + static const int Q = 'Q'; // NOLINT(readability-identifier-naming) + static const int R = 'R'; // NOLINT(readability-identifier-naming) + static const int S = 'S'; // NOLINT(readability-identifier-naming) + static const int T = 'T'; // NOLINT(readability-identifier-naming) + static const int U = 'U'; // NOLINT(readability-identifier-naming) + static const int V = 'V'; // NOLINT(readability-identifier-naming) + static const int W = 'W'; // NOLINT(readability-identifier-naming) + static const int X = 'X'; // NOLINT(readability-identifier-naming) + static const int Y = 'Y'; // NOLINT(readability-identifier-naming) + static const int Z = 'Z'; // NOLINT(readability-identifier-naming) } // namespace TAO_PEGTL_NAMESPACE::alphabet diff --git a/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp b/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp new file mode 100644 index 0000000000000000000000000000000000000000..128017d0f9397aa2b0c29f32398d102b9787fcfb --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp @@ -0,0 +1,209 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_ANALYZE_HPP +#define TAO_PEGTL_CONTRIB_ANALYZE_HPP + +#include <cassert> +#include <cstddef> +#include <iostream> +#include <map> +#include <set> +#include <stdexcept> +#include <string_view> +#include <utility> +#include <vector> + +#include "../config.hpp" + +#include "analyze_traits.hpp" + +#include "../internal/demangle.hpp" +#include "../internal/dependent_false.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + struct analyze_entry + { + explicit analyze_entry( const analyze_type in_type ) noexcept + : type( in_type ) + {} + + const analyze_type type; + std::vector< std::string_view > subs; + }; + + template< typename C > + class analyze_guard + { + public: + analyze_guard( C& container, const typename C::value_type& value ) + : m_i( container.insert( value ) ), + m_c( container ) + {} + + analyze_guard( analyze_guard&& ) = delete; + analyze_guard( const analyze_guard& ) = delete; + + void operator=( analyze_guard&& ) = delete; + void operator=( const analyze_guard& ) = delete; + + ~analyze_guard() + { + if( m_i.second ) { + m_c.erase( m_i.first ); + } + } + + explicit operator bool() const noexcept + { + return m_i.second; + } + + private: + const std::pair< typename C::iterator, bool > m_i; + C& m_c; + }; + + template< typename C > + analyze_guard( C&, const typename C::value_type& )->analyze_guard< C >; + + class analyze_cycles_impl + { + public: + analyze_cycles_impl( analyze_cycles_impl&& ) = delete; + analyze_cycles_impl( const analyze_cycles_impl& ) = delete; + + ~analyze_cycles_impl() = default; + + void operator=( analyze_cycles_impl&& ) = delete; + void operator=( const analyze_cycles_impl& ) = delete; + + [[nodiscard]] std::size_t problems() + { + for( auto i = m_info.begin(); i != m_info.end(); ++i ) { + m_results[ i->first ] = work( i, false ); + m_cache.clear(); + } + return m_problems; + } + + template< typename Rule > + [[nodiscard]] bool consumes() const + { + return m_results.at( demangle< Rule >() ); + } + + protected: + explicit analyze_cycles_impl( const bool verbose ) noexcept + : m_verbose( verbose ), + m_problems( 0 ) + {} + + [[nodiscard]] std::map< std::string_view, analyze_entry >::const_iterator find( const std::string_view name ) const noexcept + { + const auto iter = m_info.find( name ); + assert( iter != m_info.end() ); + return iter; + } + + [[nodiscard]] bool work( const std::map< std::string_view, analyze_entry >::const_iterator& start, const bool accum ) + { + if( const auto j = m_cache.find( start->first ); j != m_cache.end() ) { + return j->second; + } + if( const auto g = analyze_guard( m_stack, start->first ) ) { + switch( start->second.type ) { + case analyze_type::any: { + bool a = false; + for( const auto& r : start->second.subs ) { + a = a || work( find( r ), accum || a ); + } + return m_cache[ start->first ] = true; + } + case analyze_type::opt: { + bool a = false; + for( const auto& r : start->second.subs ) { + a = a || work( find( r ), accum || a ); + } + return m_cache[ start->first ] = false; + } + case analyze_type::seq: { + bool a = false; + for( const auto& r : start->second.subs ) { + a = a || work( find( r ), accum || a ); + } + return m_cache[ start->first ] = a; + } + case analyze_type::sor: { + bool a = true; + for( const auto& r : start->second.subs ) { + a = a && work( find( r ), accum ); + } + return m_cache[ start->first ] = a; + } + } + assert( false ); // LCOV_EXCL_LINE + } + if( !accum ) { + ++m_problems; + if( m_verbose ) { + std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl; // LCOV_EXCL_LINE + } + } + return m_cache[ start->first ] = accum; + } + + const bool m_verbose; + + std::size_t m_problems; + + std::map< std::string_view, analyze_entry > m_info; + std::set< std::string_view > m_stack; + std::map< std::string_view, bool > m_cache; + std::map< std::string_view, bool > m_results; + }; + + template< typename Name > + std::string_view analyze_insert( std::map< std::string_view, analyze_entry >& info ) + { + using Traits = analyze_traits< Name, typename Name::rule_t >; + + const auto [ i, b ] = info.try_emplace( demangle< Name >(), Traits::type_v ); + if( b ) { + analyze_insert_impl( typename Traits::subs_t(), i->second.subs, info ); + } + return i->first; + } + + template< typename... Subs > + void analyze_insert_impl( type_list< Subs... > /*unused*/, std::vector< std::string_view >& subs, std::map< std::string_view, analyze_entry >& info ) + { + ( subs.emplace_back( analyze_insert< Subs >( info ) ), ... ); + } + + template< typename Grammar > + class analyze_cycles + : public analyze_cycles_impl + { + public: + explicit analyze_cycles( const bool verbose ) + : analyze_cycles_impl( verbose ) + { + analyze_insert< Grammar >( m_info ); + } + }; + + } // namespace internal + + template< typename Grammar > + [[nodiscard]] std::size_t analyze( const bool verbose = true ) + { + return internal::analyze_cycles< Grammar >( verbose ).problems(); + } + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/analyze_traits.hpp b/packages/PEGTL/include/tao/pegtl/contrib/analyze_traits.hpp new file mode 100644 index 0000000000000000000000000000000000000000..608f35b3f34d23862c07e9515c09030dfd91a2bf --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/analyze_traits.hpp @@ -0,0 +1,275 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_ANALYZE_TRAITS_HPP +#define TAO_PEGTL_CONTRIB_ANALYZE_TRAITS_HPP + +#include <type_traits> + +#include "../ascii.hpp" +#include "../config.hpp" +#include "../rules.hpp" +#include "../type_list.hpp" + +#include "forward.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + enum class analyze_type + { + any, // Consumption-on-success is always true; assumes bounded repetition of conjunction of sub-rules. + opt, // Consumption-on-success not necessarily true; assumes bounded repetition of conjunction of sub-rules. + seq, // Consumption-on-success depends on consumption of (non-zero bounded repetition of) conjunction of sub-rules. + sor // Consumption-on-success depends on consumption of (non-zero bounded repetition of) disjunction of sub-rules. + }; + + } // namespace internal + + template< typename... Rules > + struct analyze_any_traits + { + static constexpr internal::analyze_type type_v = internal::analyze_type::any; + using subs_t = type_list< Rules... >; + }; + + template< typename... Rules > + struct analyze_opt_traits + { + static constexpr internal::analyze_type type_v = internal::analyze_type::opt; + using subs_t = type_list< Rules... >; + }; + + template< typename... Rules > + struct analyze_seq_traits + { + static constexpr internal::analyze_type type_v = internal::analyze_type::seq; + using subs_t = type_list< Rules... >; + }; + + template< typename... Rules > + struct analyze_sor_traits + { + static constexpr internal::analyze_type type_v = internal::analyze_type::sor; + using subs_t = type_list< Rules... >; + }; + + template< typename Name, template< typename... > class Action, typename... Rules > + struct analyze_traits< Name, internal::action< Action, Rules... > > + : analyze_traits< Name, typename seq< Rules... >::rule_t > + {}; + + template< typename Name, typename Peek > + struct analyze_traits< Name, internal::any< Peek > > + : analyze_any_traits<> + {}; + + template< typename Name, typename... Actions > + struct analyze_traits< Name, internal::apply< Actions... > > + : analyze_opt_traits<> + {}; + + template< typename Name, typename... Actions > + struct analyze_traits< Name, internal::apply0< Actions... > > + : analyze_opt_traits<> + {}; + + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::at< Rules... > > + : analyze_traits< Name, typename opt< Rules... >::rule_t > + {}; + + template< typename Name > + struct analyze_traits< Name, internal::bof > + : analyze_opt_traits<> + {}; + + template< typename Name > + struct analyze_traits< Name, internal::bol > + : analyze_opt_traits<> + {}; + + template< typename Name, unsigned Cnt > + struct analyze_traits< Name, internal::bytes< Cnt > > + : std::conditional_t< ( Cnt != 0 ), analyze_any_traits<>, analyze_opt_traits<> > + {}; + + template< typename Name, template< typename... > class Control, typename... Rules > + struct analyze_traits< Name, internal::control< Control, Rules... > > + : analyze_traits< Name, typename seq< Rules... >::rule_t > + {}; + + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::disable< Rules... > > + : analyze_traits< Name, typename seq< Rules... >::rule_t > + {}; + + template< typename Name > + struct analyze_traits< Name, internal::discard > + : analyze_opt_traits<> + {}; + + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::enable< Rules... > > + : analyze_traits< Name, typename seq< Rules... >::rule_t > + {}; + + template< typename Name > + struct analyze_traits< Name, internal::eof > + : analyze_opt_traits<> + {}; + + template< typename Name > + struct analyze_traits< Name, internal::eol > + : analyze_any_traits<> + {}; + + template< typename Name > + struct analyze_traits< Name, internal::eolf > + : analyze_opt_traits<> + {}; + + template< typename Name > + struct analyze_traits< Name, internal::failure > + : analyze_any_traits<> + {}; + + template< typename Name, typename Rule, typename... Actions > + struct analyze_traits< Name, internal::if_apply< Rule, Actions... > > + : analyze_traits< Name, typename Rule::rule_t > + {}; + + template< typename Name, typename Cond, typename... Rules > + struct analyze_traits< Name, internal::if_must< true, Cond, Rules... > > + : analyze_traits< Name, typename opt< Cond, Rules... >::rule_t > + {}; + + template< typename Name, typename Cond, typename... Rules > + struct analyze_traits< Name, internal::if_must< false, Cond, Rules... > > + : analyze_traits< Name, typename seq< Cond, Rules... >::rule_t > + {}; + + template< typename Name, typename Cond, typename Then, typename Else > + struct analyze_traits< Name, internal::if_then_else< Cond, Then, Else > > + : analyze_traits< Name, typename sor< seq< Cond, Then >, Else >::rule_t > + {}; + + template< typename Name, char... Cs > + struct analyze_traits< Name, internal::istring< Cs... > > + : std::conditional_t< ( sizeof...( Cs ) != 0 ), analyze_any_traits<>, analyze_opt_traits<> > + {}; + + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::must< Rules... > > + : analyze_traits< Name, typename seq< Rules... >::rule_t > + {}; + + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::not_at< Rules... > > + : analyze_traits< Name, typename opt< Rules... >::rule_t > + {}; + + template< typename Name, internal::result_on_found R, typename Peek, typename Peek::data_t... Cs > + struct analyze_traits< Name, internal::one< R, Peek, Cs... > > + : analyze_any_traits<> + {}; + + template< typename Name, typename Rule, typename... Rules > + struct analyze_traits< Name, internal::opt< Rule, Rules... > > + : analyze_opt_traits< Rule, Rules... > + {}; + + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::plus< Rules... > > + : analyze_traits< Name, typename seq< Rules..., opt< Name > >::rule_t > + {}; + + template< typename Name, typename T > + struct analyze_traits< Name, internal::raise< T > > + : analyze_any_traits<> + {}; + + template< typename Name, internal::result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi > + struct analyze_traits< Name, internal::range< R, Peek, Lo, Hi > > + : analyze_any_traits<> + {}; + + template< typename Name, typename Peek, typename Peek::data_t... Cs > + struct analyze_traits< Name, internal::ranges< Peek, Cs... > > + : analyze_any_traits<> + {}; + + template< typename Name, typename Head, typename... Rules > + struct analyze_traits< Name, internal::rematch< Head, Rules... > > + : analyze_traits< Name, typename sor< Head, sor< seq< Rules, any >... > >::rule_t > // TODO: Correct (enough)? + {}; + + template< typename Name, unsigned Cnt, typename... Rules > + struct analyze_traits< Name, internal::rep< Cnt, Rules... > > + : analyze_traits< Name, std::conditional_t< ( Cnt != 0 ), typename seq< Rules... >::rule_t, typename opt< Rules... >::rule_t > > + {}; + + template< typename Name, unsigned Min, unsigned Max, typename... Rules > + struct analyze_traits< Name, internal::rep_min_max< Min, Max, Rules... > > + : analyze_traits< Name, std::conditional_t< ( Min != 0 ), typename seq< Rules... >::rule_t, typename opt< Rules... >::rule_t > > + {}; + + template< typename Name, unsigned Max, typename... Rules > + struct analyze_traits< Name, internal::rep_opt< Max, Rules... > > + : analyze_traits< Name, typename opt< Rules... >::rule_t > + {}; + + template< typename Name, unsigned Amount > + struct analyze_traits< Name, internal::require< Amount > > + : analyze_opt_traits<> + {}; + + template< typename Name, typename Rule, typename... Rules > + struct analyze_traits< Name, internal::seq< Rule, Rules... > > + : analyze_seq_traits< Rule, Rules... > + {}; + + template< typename Name, typename Rule, typename... Rules > + struct analyze_traits< Name, internal::sor< Rule, Rules... > > + : analyze_sor_traits< Rule, Rules... > + {}; + + template< typename Name, typename... Rules > + struct analyze_traits< Name, internal::star< Rules... > > + : analyze_traits< Name, typename opt< Rules..., Name >::rule_t > + {}; + + template< typename Name, typename State, typename... Rules > + struct analyze_traits< Name, internal::state< State, Rules... > > + : analyze_traits< Name, typename seq< Rules... >::rule_t > + {}; + + template< typename Name, char... Cs > + struct analyze_traits< Name, internal::string< Cs... > > + : std::conditional_t< ( sizeof...( Cs ) != 0 ), analyze_any_traits<>, analyze_opt_traits<> > + {}; + + template< typename Name > + struct analyze_traits< Name, internal::success > + : analyze_opt_traits<> + {}; + + template< typename Name, typename Exception, typename... Rules > + struct analyze_traits< Name, internal::try_catch_type< Exception, Rules... > > + : analyze_traits< Name, typename seq< Rules... >::rule_t > + {}; + + template< typename Name, typename Cond > + struct analyze_traits< Name, internal::until< Cond > > + : analyze_traits< Name, typename Cond::rule_t > + {}; + + template< typename Name, typename Cond, typename... Rules > + struct analyze_traits< Name, internal::until< Cond, Rules... > > + : analyze_traits< Name, typename seq< star< Rules... >, Cond >::rule_t > + {}; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/counter.hpp b/packages/PEGTL/include/tao/pegtl/contrib/counter.hpp deleted file mode 100644 index fab396f936736fbb5742c00d60231feacef768c3..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/contrib/counter.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_CONTRIB_COUNTER_HPP -#define TAO_PEGTL_CONTRIB_COUNTER_HPP - -#include <map> -#include <string> - -#include "../config.hpp" -#include "../normal.hpp" - -#include "../internal/demangle.hpp" - -namespace TAO_PEGTL_NAMESPACE -{ - struct counter_data - { - unsigned start = 0; - unsigned success = 0; - unsigned failure = 0; - }; - - struct counter_state - { - std::map< std::string, counter_data > counts; - }; - - template< typename Rule > - struct counter - : normal< Rule > - { - template< typename Input > - static void start( const Input& /*unused*/, counter_state& ts ) - { - ++ts.counts[ internal::demangle< Rule >() ].start; - } - - template< typename Input > - static void success( const Input& /*unused*/, counter_state& ts ) - { - ++ts.counts[ internal::demangle< Rule >() ].success; - } - - template< typename Input > - static void failure( const Input& /*unused*/, counter_state& ts ) - { - ++ts.counts[ internal::demangle< Rule >() ].failure; - } - }; - -} // namespace TAO_PEGTL_NAMESPACE - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp b/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..582813a8c6de1a450eeb3cb5770fab60d1bd05c1 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp @@ -0,0 +1,159 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_COVERAGE_HPP +#define TAO_PEGTL_CONTRIB_COVERAGE_HPP + +#include <cassert> +#include <cstddef> +#include <map> +#include <string> +#include <string_view> +#include <vector> + +#include "remove_first_state.hpp" +#include "shuffle_states.hpp" + +#include "../config.hpp" +#include "../normal.hpp" +#include "../nothing.hpp" +#include "../parse.hpp" +#include "../type_list.hpp" +#include "../visit.hpp" + +#include "../internal/demangle.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + struct coverage_info + { + std::size_t start = 0; + std::size_t success = 0; + std::size_t local_failure = 0; + std::size_t global_failure = 0; + std::size_t raise = 0; + }; + + struct coverage_entry + : coverage_info + { + std::map< std::string_view, coverage_info > branches; + }; + + struct coverage_state + { + std::string_view grammar; + std::string source; + + std::map< std::string_view, coverage_entry > map; + bool result; + + std::vector< std::string_view > stack; + }; + + namespace internal + { + template< typename Rule > + struct coverage_insert + { + static void visit( coverage_state& state ) + { + visit_branches( state.map.try_emplace( internal::demangle< Rule >() ).first->second.branches, typename Rule::subs_t() ); + } + + template< typename... Ts > + static void visit_branches( std::map< std::string_view, coverage_info >& branches, type_list< Ts... > /*unused*/ ) + { + ( branches.try_emplace( internal::demangle< Ts >() ), ... ); + } + }; + + template< template< typename... > class Control = normal > + struct make_coverage_control + { + template< typename Rule > + struct control + : remove_first_state< Control< Rule > > + { + template< typename ParseInput, typename... States > + [[noreturn]] static void raise( const ParseInput& in, coverage_state& state, States&&... st ) + { + const auto name = internal::demangle< Rule >(); + ++state.map.at( name ).raise; + if( state.stack.size() > 1 ) { + ++state.map.at( state.stack.at( state.stack.size() - 2 ) ).branches.at( name ).raise; + } + Control< Rule >::raise( in, st... ); + } + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control2, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) + { + coverage_entry dummy; + auto& state = std::get< sizeof...( st ) - 1 >( std::tie( st... ) ); + const auto name = internal::demangle< Rule >(); + auto& entry = state.map.at( name ); + auto& previous = state.stack.empty() ? dummy : state.map.at( state.stack.back() ).branches.at( name ); + ++entry.start; + ++previous.start; + state.stack.push_back( name ); + try { + const bool result = Control< Rule >::template match< A, M, Action, Control2 >( in, st... ); + state.stack.pop_back(); + if( result ) { + ++entry.success; + ++previous.success; + } + else { + ++entry.local_failure; + ++previous.local_failure; + } + return result; + } + catch( ... ) { + state.stack.pop_back(); + ++entry.global_failure; + ++previous.global_failure; + throw; + } + } + }; + + template< typename Rule > + using type = rotate_states_right< control< Rule > >; + }; + + } // namespace internal + + template< typename Rule, + template< typename... > class Action = nothing, + template< typename... > class Control = normal, + typename ParseInput, + typename... States > + coverage_state coverage( ParseInput&& in, States&&... st ) + { + coverage_state state; + + state.grammar = internal::demangle< Rule >(); + state.source = in.source(); + + // populate state + visit< Rule, internal::coverage_insert >( state ); + + // parse + state.result = parse< Rule, Action, internal::make_coverage_control<>::template type >( in, st..., state ); + assert( state.stack.empty() ); + + return state; + } + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/forward.hpp b/packages/PEGTL/include/tao/pegtl/contrib/forward.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4e2a592ef95accdc4e4b82dec6ceaf0edff50578 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/forward.hpp @@ -0,0 +1,16 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_FORWARD_HPP +#define TAO_PEGTL_CONTRIB_FORWARD_HPP + +#include "../config.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + template< typename Name, typename Rule, typename = void > + struct analyze_traits; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/http.hpp b/packages/PEGTL/include/tao/pegtl/contrib/http.hpp index 3d28f466a10b920119c849452c4ca7d87640400a..74b0e9eb7f080ea6570217e3cfd879a5b4307576 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/http.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/http.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_HTTP_HPP @@ -6,10 +6,13 @@ #include "../ascii.hpp" #include "../config.hpp" +#include "../nothing.hpp" #include "../rules.hpp" #include "../utf8.hpp" #include "abnf.hpp" +#include "forward.hpp" +#include "remove_first_state.hpp" #include "uri.hpp" namespace TAO_PEGTL_NAMESPACE::http @@ -120,17 +123,144 @@ namespace TAO_PEGTL_NAMESPACE::http struct partial_URI : seq< uri::relative_part, uri::opt_query > {}; - struct chunk_size : plus< abnf::HEXDIG > {}; + // clang-format on + struct chunk_size + { + using rule_t = plus< abnf::HEXDIG >::rule_t; + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, std::size_t& size, States&&... /*unused*/ ) + { + size = 0; + std::size_t i = 0; + while( in.size( i + 1 ) >= i + 1 ) { + const auto c = in.peek_char( i ); + if( ( '0' <= c ) && ( c <= '9' ) ) { + size <<= 4; + size |= std::size_t( c - '0' ); + ++i; + continue; + } + if( ( 'a' <= c ) && ( c <= 'f' ) ) { + size <<= 4; + size |= std::size_t( c - 'a' + 10 ); + ++i; + continue; + } + if( ( 'A' <= c ) && ( c <= 'F' ) ) { + size <<= 4; + size |= std::size_t( c - 'A' + 10 ); + ++i; + continue; + } + break; + } + in.bump_in_this_line( i ); + return i > 0; + } + }; + // clang-format off struct chunk_ext_name : token {}; struct chunk_ext_val : sor< quoted_string, token > {}; struct chunk_ext : star_must< one< ';' >, chunk_ext_name, if_must< one< '=' >, chunk_ext_val > > {}; - struct chunk_data : until< at< abnf::CRLF >, abnf::OCTET > {}; - - struct chunk : seq< chunk_size, opt< chunk_ext >, abnf::CRLF, chunk_data, abnf::CRLF > {}; + // clang-format on + struct chunk_data + { + using rule_t = star< abnf::OCTET >::rule_t; + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, const std::size_t size, States&&... /*unused*/ ) + { + if( in.size( size ) >= size ) { + in.bump( size ); + return true; + } + return false; + } + }; + + namespace internal::chunk_helper + { + template< typename Base > + struct control; + + template< template< typename... > class Control, typename Rule > + struct control< Control< Rule > > + : Control< Rule > + { + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class, + typename ParseInput, + typename State, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, State&& /*unused*/, States&&... st ) + { + return Control< Rule >::template match< A, M, Action, Control >( in, st... ); + } + }; + + template< template< typename... > class Control > + struct control< Control< chunk_size > > + : remove_first_state< Control< chunk_size > > + {}; + + template< template< typename... > class Control > + struct control< Control< chunk_data > > + : remove_first_state< Control< chunk_data > > + {}; + + template< template< typename... > class Control > + struct bind + { + template< typename Rule > + using type = control< Control< Rule > >; + }; + + } // namespace internal::chunk_helper + + struct chunk + { + using impl = seq< chunk_size, chunk_ext, abnf::CRLF, chunk_data, abnf::CRLF >; + + using rule_t = impl::rule_t; + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) + { + std::size_t size{}; + return impl::template match< A, M, Action, internal::chunk_helper::bind< Control >::template type >( in, size, st... ); + } + }; - struct last_chunk : seq< plus< one< '0' > >, opt< chunk_ext >, abnf::CRLF > {}; + // clang-format off + struct last_chunk : seq< plus< one< '0' > >, not_at< digit >, chunk_ext, abnf::CRLF > {}; struct trailer_part : star< header_field, abnf::CRLF > {}; diff --git a/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp b/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp index c71bac3429e598bd609a57a8dfb2fa856aa5188e..9ee98a1420d5682e5523a10bc6b1c0f696da1c9c 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_ICU_INTERNAL_HPP @@ -7,9 +7,9 @@ #include <unicode/uchar.h> #include "../../config.hpp" +#include "../../type_list.hpp" -#include "../../analysis/generic.hpp" -#include "../../internal/skip_control.hpp" +#include "../../internal/enable_control.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -18,17 +18,16 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Peek, UProperty P, bool V = true > struct binary_property { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = binary_property; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) ) { - if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) { - if( const auto r = Peek::peek( in, s ) ) { - if( u_hasBinaryProperty( r.data, P ) == V ) { - in.bump( r.size ); - return true; - } + if( const auto r = Peek::peek( in ) ) { + if( u_hasBinaryProperty( r.data, P ) == V ) { + in.bump( r.size ); + return true; } } return false; @@ -38,17 +37,16 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Peek, UProperty P, int V > struct property_value { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = property_value; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) ) { - if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) { - if( const auto r = Peek::peek( in, s ) ) { - if( u_getIntPropertyValue( r.data, P ) == V ) { - in.bump( r.size ); - return true; - } + if( const auto r = Peek::peek( in ) ) { + if( u_getIntPropertyValue( r.data, P ) == V ) { + in.bump( r.size ); + return true; } } return false; @@ -58,10 +56,10 @@ namespace TAO_PEGTL_NAMESPACE::internal } // namespace icu template< typename Peek, UProperty P, bool V > - inline constexpr bool skip_control< icu::binary_property< Peek, P, V > > = true; + inline constexpr bool enable_control< icu::binary_property< Peek, P, V > > = false; template< typename Peek, UProperty P, int V > - inline constexpr bool skip_control< icu::property_value< Peek, P, V > > = true; + inline constexpr bool enable_control< icu::property_value< Peek, P, V > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp index 316eb84c375633f09a30f49fb1a61b898370b5bc..22c05ba0f1cc899682a95575313dc7fe78cd7e3a 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_ICU_UTF16_HPP @@ -7,9 +7,9 @@ #include "internal.hpp" #include "../../config.hpp" -#include "../../utf16.hpp" +#include "../utf16.hpp" -#include "../../internal/peek_utf16.hpp" +#include "../internal/peek_utf16.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -18,14 +18,12 @@ namespace TAO_PEGTL_NAMESPACE template< UProperty P, bool V = true > struct binary_property : internal::icu::binary_property< internal::peek_utf16_be, P, V > - { - }; + {}; template< UProperty P, int V > struct property_value : internal::icu::property_value< internal::peek_utf16_be, P, V > - { - }; + {}; // clang-format off struct alphabetic : binary_property< UCHAR_ALPHABETIC > {}; @@ -109,14 +107,12 @@ namespace TAO_PEGTL_NAMESPACE template< UProperty P, bool V = true > struct binary_property : internal::icu::binary_property< internal::peek_utf16_le, P, V > - { - }; + {}; template< UProperty P, int V > struct property_value : internal::icu::property_value< internal::peek_utf16_le, P, V > - { - }; + {}; // clang-format off struct alphabetic : binary_property< UCHAR_ALPHABETIC > {}; diff --git a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp index 8c7189edfe6d2d2cdcab4968afb7ddb645565516..aa59b04c753c58c5ca0b8fdbf28335e09f705c31 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_ICU_UTF32_HPP @@ -7,9 +7,9 @@ #include "internal.hpp" #include "../../config.hpp" -#include "../../utf32.hpp" +#include "../utf32.hpp" -#include "../../internal/peek_utf32.hpp" +#include "../internal/peek_utf32.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -18,14 +18,12 @@ namespace TAO_PEGTL_NAMESPACE template< UProperty P, bool V = true > struct binary_property : internal::icu::binary_property< internal::peek_utf32_be, P, V > - { - }; + {}; template< UProperty P, int V > struct property_value : internal::icu::property_value< internal::peek_utf32_be, P, V > - { - }; + {}; // clang-format off struct alphabetic : binary_property< UCHAR_ALPHABETIC > {}; @@ -109,14 +107,12 @@ namespace TAO_PEGTL_NAMESPACE template< UProperty P, bool V = true > struct binary_property : internal::icu::binary_property< internal::peek_utf32_le, P, V > - { - }; + {}; template< UProperty P, int V > struct property_value : internal::icu::property_value< internal::peek_utf32_le, P, V > - { - }; + {}; // clang-format off struct alphabetic : binary_property< UCHAR_ALPHABETIC > {}; diff --git a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf8.hpp b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf8.hpp index 7c7cc5573b2f617a61a6badfae57fa89c07da565..aaf6838d3051082c8975ace45fe06ead8c6483af 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf8.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf8.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_ICU_UTF8_HPP @@ -16,14 +16,12 @@ namespace TAO_PEGTL_NAMESPACE::utf8::icu template< UProperty P, bool V = true > struct binary_property : internal::icu::binary_property< internal::peek_utf8, P, V > - { - }; + {}; template< UProperty P, int V > struct property_value : internal::icu::property_value< internal::peek_utf8, P, V > - { - }; + {}; // clang-format off struct alphabetic : binary_property< UCHAR_ALPHABETIC > {}; diff --git a/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp b/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp index 63e4e9c96f5fbd5810c7de401cce01083e194823..734523c75376ca14bd933447c1f0ed21dafb8325 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_IF_THEN_HPP @@ -8,10 +8,11 @@ #include "../config.hpp" +#include "../internal/enable_control.hpp" +#include "../internal/failure.hpp" #include "../internal/if_then_else.hpp" #include "../internal/seq.hpp" -#include "../internal/skip_control.hpp" -#include "../internal/trivial.hpp" +#include "../internal/success.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -19,8 +20,7 @@ namespace TAO_PEGTL_NAMESPACE { template< typename Cond, typename Then > struct if_pair - { - }; + {}; template< typename... Pairs > struct if_then; @@ -33,22 +33,23 @@ namespace TAO_PEGTL_NAMESPACE using else_if_then = if_then< if_pair< Cond, Then >, Pairs..., if_pair< ElseCond, seq< Thens... > > >; template< typename... Thens > - using else_then = if_then_else< Cond, Then, if_then< Pairs..., if_pair< trivial< true >, seq< Thens... > > > >; + using else_then = if_then_else< Cond, Then, if_then< Pairs..., if_pair< success, seq< Thens... > > > >; }; template<> struct if_then<> - : trivial< false > - { - }; + : failure + {}; template< typename... Pairs > - inline constexpr bool skip_control< if_then< Pairs... > > = true; + inline constexpr bool enable_control< if_then< Pairs... > > = false; } // namespace internal template< typename Cond, typename... Thens > - using if_then = internal::if_then< internal::if_pair< Cond, internal::seq< Thens... > > >; + struct if_then + : internal::if_then< internal::if_pair< Cond, internal::seq< Thens... > > > + {}; } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp b/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp index 77d11421bb033414df96df4506356efeec04de5c..9bbbf9977be4e39782f869ee288758fe33b34157 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp @@ -1,77 +1,357 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_INTEGER_HPP #define TAO_PEGTL_CONTRIB_INTEGER_HPP -#include <limits> +#include <cstdint> +#include <cstdlib> + #include <type_traits> #include "../ascii.hpp" +#include "../parse.hpp" #include "../parse_error.hpp" #include "../rules.hpp" -namespace TAO_PEGTL_NAMESPACE::integer +#include "analyze_traits.hpp" + +namespace TAO_PEGTL_NAMESPACE { + struct unsigned_rule_old + : plus< digit > + { + // Pre-3.0 version of this rule. + }; + + struct unsigned_rule_new + : if_then_else< one< '0' >, not_at< digit >, plus< digit > > + { + // New version that does not allow leading zeros. + }; + + struct signed_rule_old + : seq< opt< one< '-', '+' > >, plus< digit > > + { + // Pre-3.0 version of this rule. + }; + + struct signed_rule_new + : seq< opt< one< '-', '+' > >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > > + { + // New version that does not allow leading zeros. + }; + + struct signed_rule_bis + : seq< opt< one< '-' > >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > > + {}; + + struct signed_rule_ter + : seq< one< '-', '+' >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > > + {}; + namespace internal { - template< typename I, I Limit, typename Input > - [[nodiscard]] I actual_convert( const Input& in, std::size_t index ) + [[nodiscard]] constexpr bool is_digit( const char c ) noexcept + { + // We don't use std::isdigit() because it might + // return true for other values on MS platforms. + + return ( '0' <= c ) && ( c <= '9' ); + } + + template< typename Integer, Integer Maximum = ( std::numeric_limits< Integer >::max )() > + [[nodiscard]] constexpr bool accumulate_digit( Integer& result, const char digit ) noexcept + { + // Assumes that digit is a digit as per is_digit(); returns false on overflow. + + static_assert( std::is_integral_v< Integer > ); + + constexpr Integer cutoff = Maximum / 10; + constexpr Integer cutlim = Maximum % 10; + + const Integer c = digit - '0'; + + if( ( result > cutoff ) || ( ( result == cutoff ) && ( c > cutlim ) ) ) { + return false; + } + result *= 10; + result += c; + return true; + } + + template< typename Integer, Integer Maximum = ( std::numeric_limits< Integer >::max )() > + [[nodiscard]] constexpr bool accumulate_digits( Integer& result, const std::string_view input ) noexcept { - static constexpr I cutoff = Limit / 10; - static constexpr I cutlim = Limit % 10; + // Assumes input is a non-empty sequence of digits; returns false on overflow. - I out = in.peek_char( index ) - '0'; - while( ++index < in.size() ) { - const I c = in.peek_char( index ) - '0'; - if( ( out > cutoff ) || ( ( out == cutoff ) && ( c > cutlim ) ) ) { - throw parse_error( "integer out of range", in ); + for( char c : input ) { + if( !accumulate_digit< Integer, Maximum >( result, c ) ) { + return false; } - out *= 10; - out += c; } - return out; + return true; } - template< typename I, typename Input > - [[nodiscard]] I convert_positive( const Input& in, std::size_t index ) + template< typename Integer, Integer Maximum = ( std::numeric_limits< Integer >::max )() > + [[nodiscard]] constexpr bool convert_positive( Integer& result, const std::string_view input ) noexcept { - static constexpr I limit = ( std::numeric_limits< I >::max )(); - return actual_convert< I, limit >( in, index ); + // Assumes result == 0 and that input is a non-empty sequence of digits; returns false on overflow. + + static_assert( std::is_integral_v< Integer > ); + return accumulate_digits< Integer, Maximum >( result, input ); } - template< typename I, typename Input > - [[nodiscard]] I convert_negative( const Input& in, std::size_t index ) + template< typename Signed > + [[nodiscard]] constexpr bool convert_negative( Signed& result, const std::string_view input ) noexcept { - using U = std::make_unsigned_t< I >; - static constexpr U limit = static_cast< U >( ( std::numeric_limits< I >::max )() ) + 1; - return static_cast< I >( ~actual_convert< U, limit >( in, index ) ) + 1; + // Assumes result == 0 and that input is a non-empty sequence of digits; returns false on overflow. + + static_assert( std::is_signed_v< Signed > ); + using Unsigned = std::make_unsigned_t< Signed >; + constexpr Unsigned maximum = static_cast< Unsigned >( ( std::numeric_limits< Signed >::max )() ) + 1; + Unsigned temporary = 0; + if( accumulate_digits< Unsigned, maximum >( temporary, input ) ) { + result = static_cast< Signed >( ~temporary ) + 1; + return true; + } + return false; + } + + template< typename Unsigned, Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() > + [[nodiscard]] constexpr bool convert_unsigned( Unsigned& result, const std::string_view input ) noexcept + { + // Assumes result == 0 and that input is a non-empty sequence of digits; returns false on overflow. + + static_assert( std::is_unsigned_v< Unsigned > ); + return accumulate_digits< Unsigned, Maximum >( result, input ); + } + + template< typename Signed > + [[nodiscard]] constexpr bool convert_signed( Signed& result, const std::string_view input ) noexcept + { + // Assumes result == 0 and that input is an optional sign followed by a non-empty sequence of digits; returns false on overflow. + + static_assert( std::is_signed_v< Signed > ); + if( input[ 0 ] == '-' ) { + return convert_negative< Signed >( result, std::string_view( input.data() + 1, input.size() - 1 ) ); + } + const auto offset = unsigned( input[ 0 ] == '+' ); + return convert_positive< Signed >( result, std::string_view( input.data() + offset, input.size() - offset ) ); + } + + template< typename ParseInput > + [[nodiscard]] bool match_unsigned( ParseInput& in ) noexcept( noexcept( in.empty() ) ) + { + if( !in.empty() ) { + const char c = in.peek_char(); + if( is_digit( c ) ) { + in.bump_in_this_line(); + if( c == '0' ) { + return in.empty() || ( !is_digit( in.peek_char() ) ); // TODO: Throw exception on digit? + } + while( ( !in.empty() ) && is_digit( in.peek_char() ) ) { + in.bump_in_this_line(); + } + return true; + } + } + return false; + } + + template< typename ParseInput, + typename Unsigned, + Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() > + [[nodiscard]] bool match_and_convert_unsigned_with_maximum( ParseInput& in, Unsigned& st ) + { + // Assumes st == 0. + + if( !in.empty() ) { + char c = in.peek_char(); + if( is_digit( c ) ) { + if( c == '0' ) { + in.bump_in_this_line(); + return in.empty() || ( !is_digit( in.peek_char() ) ); // TODO: Throw exception on digit? + } + do { + if( !accumulate_digit< Unsigned, Maximum >( st, c ) ) { + throw parse_error( "integer overflow", in ); // Consistent with "as if" an action was doing the conversion. + } + in.bump_in_this_line(); + } while( ( !in.empty() ) && is_digit( c = in.peek_char() ) ); + return true; + } + } + return false; } } // namespace internal + struct unsigned_action + { + // Assumes that 'in' contains a non-empty sequence of ASCII digits. + + template< typename ActionInput, typename Unsigned > + static auto apply( const ActionInput& in, Unsigned& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void > + { + // This function "only" offers basic exception safety. + st = 0; + if( !internal::convert_unsigned( st, in.string_view() ) ) { + throw parse_error( "unsigned integer overflow", in ); + } + } + + template< typename ActionInput, typename State > + static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void > + { + apply( in, st.converted ); // Compatibility for pre-3.0 behaviour. + } + + template< typename ActionInput, typename Unsigned, typename... Ts > + static auto apply( const ActionInput& in, std::vector< Unsigned, Ts... >& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void > + { + Unsigned u = 0; + apply( in, u ); + st.emplace_back( u ); + } + }; + struct unsigned_rule - : plus< digit > { + using rule_t = unsigned_rule; + using subs_t = empty_list; + + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) ) + { + return internal::match_unsigned( in ); // Does not check for any overflow. + } + }; + + struct unsigned_rule_with_action + { + using rule_t = unsigned_rule_with_action; + using subs_t = empty_list; + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ ) noexcept( noexcept( in.empty() ) ) -> std::enable_if_t< A == apply_mode::nothing, bool > + { + return internal::match_unsigned( in ); // Does not check for any overflow. + } + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename Unsigned > + [[nodiscard]] static auto match( ParseInput& in, Unsigned& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_unsigned_v< Unsigned >, bool > + { + // This function "only" offers basic exception safety. + st = 0; + return internal::match_and_convert_unsigned_with_maximum( in, st ); // Throws on overflow. + } + + // TODO: Overload for st.converted? + // TODO: Overload for std::vector< Unsigned >? }; - struct unsigned_action + template< typename Unsigned, Unsigned Maximum > + struct maximum_action { // Assumes that 'in' contains a non-empty sequence of ASCII digits. - template< typename Input, typename State > - static void apply( const Input& in, State& st ) + static_assert( std::is_unsigned_v< Unsigned > ); + + template< typename ActionInput, typename Unsigned2 > + static auto apply( const ActionInput& in, Unsigned2& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void > + { + // This function "only" offers basic exception safety. + st = 0; + if( !internal::convert_unsigned< Unsigned, Maximum >( st, in.string_view() ) ) { + throw parse_error( "unsigned integer overflow", in ); + } + } + + template< typename ActionInput, typename State > + static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void > + { + apply( in, st.converted ); // Compatibility for pre-3.0 behaviour. + } + + template< typename ActionInput, typename Unsigned2, typename... Ts > + static auto apply( const ActionInput& in, std::vector< Unsigned2, Ts... >& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void > { - using T = std::decay_t< decltype( st.converted ) >; - static_assert( std::is_integral_v< T > ); - static_assert( std::is_unsigned_v< T > ); - st.converted = internal::convert_positive< T >( in, 0 ); + Unsigned u = 0; + apply( in, u ); + st.emplace_back( u ); } }; - struct signed_rule - : seq< opt< one< '+', '-' > >, plus< digit > > + template< typename Unsigned, Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() > + struct maximum_rule + { + using rule_t = maximum_rule; + using subs_t = empty_list; + + static_assert( std::is_unsigned_v< Unsigned > ); + + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) + { + Unsigned st = 0; + return internal::match_and_convert_unsigned_with_maximum< ParseInput, Unsigned, Maximum >( in, st ); // Throws on overflow. + } + }; + + template< typename Unsigned, Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() > + struct maximum_rule_with_action { + using rule_t = maximum_rule_with_action; + using subs_t = empty_list; + + static_assert( std::is_unsigned_v< Unsigned > ); + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ ) -> std::enable_if_t< A == apply_mode::nothing, bool > + { + Unsigned st = 0; + return internal::match_and_convert_unsigned_with_maximum< ParseInput, Unsigned, Maximum >( in, st ); // Throws on overflow. + } + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename Unsigned2 > + [[nodiscard]] static auto match( ParseInput& in, Unsigned2& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_same_v< Unsigned, Unsigned2 >, bool > + { + // This function "only" offers basic exception safety. + st = 0; + return internal::match_and_convert_unsigned_with_maximum< ParseInput, Unsigned, Maximum >( in, st ); // Throws on overflow. + } + + // TODO: Overload for st.converted? + // TODO: Overload for std::vector< Unsigned >? }; struct signed_action @@ -79,22 +359,122 @@ namespace TAO_PEGTL_NAMESPACE::integer // Assumes that 'in' contains a non-empty sequence of ASCII digits, // with optional leading sign; with sign, in.size() must be >= 2. - template< typename Input, typename State > - static void apply( const Input& in, State& st ) + template< typename ActionInput, typename Signed > + static auto apply( const ActionInput& in, Signed& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void > { - using T = std::decay_t< decltype( st.converted ) >; - static_assert( std::is_integral_v< T > ); - static_assert( std::is_signed_v< T > ); - const auto c = in.peek_char(); - if( c == '-' ) { - st.converted = internal::convert_negative< T >( in, 1 ); - } - else { - st.converted = internal::convert_positive< T >( in, std::size_t( c == '+' ) ); + // This function "only" offers basic exception safety. + st = 0; + if( !internal::convert_signed( st, in.string_view() ) ) { + throw parse_error( "signed integer overflow", in ); } } + + template< typename ActionInput, typename State > + static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void > + { + apply( in, st.converted ); // Compatibility for pre-3.0 behaviour. + } + + template< typename ActionInput, typename Signed, typename... Ts > + static auto apply( const ActionInput& in, std::vector< Signed, Ts... >& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void > + { + Signed s = 0; + apply( in, s ); + st.emplace_back( s ); + } + }; + + struct signed_rule + { + using rule_t = signed_rule; + using subs_t = empty_list; + + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) ) + { + return TAO_PEGTL_NAMESPACE::parse< signed_rule_new >( in ); // Does not check for any overflow. + } }; -} // namespace TAO_PEGTL_NAMESPACE::integer + namespace internal + { + template< typename Rule > + struct signed_action_action + : nothing< Rule > + {}; + + template<> + struct signed_action_action< signed_rule_new > + : signed_action + {}; + + } // namespace internal + + struct signed_rule_with_action + { + using rule_t = signed_rule_with_action; + using subs_t = empty_list; + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ ) noexcept( noexcept( in.empty() ) ) -> std::enable_if_t< A == apply_mode::nothing, bool > + { + return TAO_PEGTL_NAMESPACE::parse< signed_rule_new >( in ); // Does not check for any overflow. + } + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename Signed > + [[nodiscard]] static auto match( ParseInput& in, Signed& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_signed_v< Signed >, bool > + { + return TAO_PEGTL_NAMESPACE::parse< signed_rule_new, internal::signed_action_action >( in, st ); // Throws on overflow. + } + + // TODO: Overload for st.converted? + // TODO: Overload for std::vector< Signed >? + }; + + template< typename Name > + struct analyze_traits< Name, unsigned_rule > + : analyze_any_traits<> + {}; + + template< typename Name > + struct analyze_traits< Name, unsigned_rule_with_action > + : analyze_any_traits<> + {}; + + template< typename Name, typename Integer, Integer Maximum > + struct analyze_traits< Name, maximum_rule< Integer, Maximum > > + : analyze_any_traits<> + {}; + + template< typename Name, typename Integer, Integer Maximum > + struct analyze_traits< Name, maximum_rule_with_action< Integer, Maximum > > + : analyze_any_traits<> + {}; + + template< typename Name > + struct analyze_traits< Name, signed_rule > + : analyze_any_traits<> + {}; + + template< typename Name > + struct analyze_traits< Name, signed_rule_with_action > + : analyze_any_traits<> + {}; + +} // namespace TAO_PEGTL_NAMESPACE #endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/endian.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian.hpp similarity index 82% rename from packages/PEGTL/include/tao/pegtl/internal/endian.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/endian.hpp index 733248ec8bca5096607381cef98394d44738d9c8..9edcd67d0b49ea85fc14e7ec097ab7d5587b50e5 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/endian.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian.hpp @@ -1,15 +1,15 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_ENDIAN_HPP -#define TAO_PEGTL_INTERNAL_ENDIAN_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_HPP #include <cstdint> #include <cstring> -#include "../config.hpp" +#include "../../config.hpp" -#if defined( _WIN32 ) && !defined( __MINGW32__ ) +#if defined( _WIN32 ) && !defined( __MINGW32__ ) && !defined( __CYGWIN__ ) #include "endian_win.hpp" #else #include "endian_gcc.hpp" diff --git a/packages/PEGTL/include/tao/pegtl/internal/endian_gcc.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_gcc.hpp similarity index 82% rename from packages/PEGTL/include/tao/pegtl/internal/endian_gcc.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/endian_gcc.hpp index 0079e3de5bc63251e416015c825a02d4a962525e..55f96d71a658be481c41c6b81ff868b323caf8af 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/endian_gcc.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_gcc.hpp @@ -1,8 +1,8 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_ENDIAN_GCC_HPP -#define TAO_PEGTL_INTERNAL_ENDIAN_GCC_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_GCC_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_GCC_HPP #include <cstdint> #include <cstring> @@ -13,7 +13,7 @@ namespace TAO_PEGTL_NAMESPACE::internal #error No byte order defined! #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - template< unsigned S > + template< std::size_t S > struct to_and_from_be { template< typename T > @@ -23,7 +23,7 @@ namespace TAO_PEGTL_NAMESPACE::internal } }; - template< unsigned S > + template< std::size_t S > struct to_and_from_le; template<> @@ -45,7 +45,7 @@ namespace TAO_PEGTL_NAMESPACE::internal { [[nodiscard]] static std::int16_t convert( const std::int16_t n ) noexcept { - return __builtin_bswap16( n ); + return static_cast< std::int16_t >( __builtin_bswap16( static_cast< std::uint16_t >( n ) ) ); } [[nodiscard]] static std::uint16_t convert( const std::uint16_t n ) noexcept @@ -68,7 +68,7 @@ namespace TAO_PEGTL_NAMESPACE::internal [[nodiscard]] static std::int32_t convert( const std::int32_t n ) noexcept { - return __builtin_bswap32( n ); + return static_cast< std::int32_t >( __builtin_bswap32( static_cast< std::uint32_t >( n ) ) ); } [[nodiscard]] static std::uint32_t convert( const std::uint32_t n ) noexcept @@ -91,7 +91,7 @@ namespace TAO_PEGTL_NAMESPACE::internal [[nodiscard]] static std::int64_t convert( const std::int64_t n ) noexcept { - return __builtin_bswap64( n ); + return static_cast< std::int64_t >( __builtin_bswap64( static_cast< std::uint64_t >( n ) ) ); } [[nodiscard]] static std::uint64_t convert( const std::uint64_t n ) noexcept @@ -106,7 +106,7 @@ namespace TAO_PEGTL_NAMESPACE::internal #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - template< unsigned S > + template< std::size_t S > struct to_and_from_le { template< typename T > @@ -116,7 +116,7 @@ namespace TAO_PEGTL_NAMESPACE::internal } }; - template< unsigned S > + template< std::size_t S > struct to_and_from_be; template<> @@ -138,7 +138,7 @@ namespace TAO_PEGTL_NAMESPACE::internal { [[nodiscard]] static std::int16_t convert( const std::int16_t n ) noexcept { - return __builtin_bswap16( n ); + return static_cast< std::int16_t >( __builtin_bswap16( static_cast< std::uint16_t >( n ) ) ); } [[nodiscard]] static std::uint16_t convert( const std::uint16_t n ) noexcept @@ -161,7 +161,7 @@ namespace TAO_PEGTL_NAMESPACE::internal [[nodiscard]] static std::int32_t convert( const std::int32_t n ) noexcept { - return __builtin_bswap32( n ); + return static_cast< std::int32_t >( __builtin_bswap32( static_cast< std::uint32_t >( n ) ) ); } [[nodiscard]] static std::uint32_t convert( const std::uint32_t n ) noexcept @@ -182,12 +182,12 @@ namespace TAO_PEGTL_NAMESPACE::internal return n; } - [[nodiscard]] static std::uint64_t convert( const std::uint64_t n ) noexcept + [[nodiscard]] static std::int64_t convert( const std::int64_t n ) noexcept { - return __builtin_bswap64( n ); + return static_cast< std::int64_t >( __builtin_bswap64( static_cast< std::uint64_t >( n ) ) ); } - [[nodiscard]] static std::int64_t convert( const std::int64_t n ) noexcept + [[nodiscard]] static std::uint64_t convert( const std::uint64_t n ) noexcept { return __builtin_bswap64( n ); } diff --git a/packages/PEGTL/include/tao/pegtl/internal/endian_win.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_win.hpp similarity index 91% rename from packages/PEGTL/include/tao/pegtl/internal/endian_win.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/endian_win.hpp index 63e92ff2df667aa906679cd8a325fbdf33521250..db0b835c9862925d47a9e4ba5b4bb4a7e5c23bf6 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/endian_win.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_win.hpp @@ -1,8 +1,8 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_ENDIAN_WIN_HPP -#define TAO_PEGTL_INTERNAL_ENDIAN_WIN_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_WIN_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_WIN_HPP #include <cstdint> #include <cstdlib> @@ -10,7 +10,7 @@ namespace TAO_PEGTL_NAMESPACE::internal { - template< unsigned S > + template< std::size_t S > struct to_and_from_le { template< typename T > @@ -20,7 +20,7 @@ namespace TAO_PEGTL_NAMESPACE::internal } }; - template< unsigned S > + template< std::size_t S > struct to_and_from_be; template<> diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint.hpp similarity index 70% rename from packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint.hpp index d99addf78af14bc51f5477a87a512f123a9464f0..e5930c104a482981dc74d628676283fbc8be9e44 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint.hpp @@ -1,15 +1,15 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_PEEK_MASK_UINT_HPP -#define TAO_PEGTL_INTERNAL_PEEK_MASK_UINT_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT_HPP #include <cstddef> #include <cstdint> -#include "../config.hpp" +#include "../../config.hpp" +#include "../../internal/input_pair.hpp" -#include "input_pair.hpp" #include "read_uint.hpp" namespace TAO_PEGTL_NAMESPACE::internal @@ -20,12 +20,12 @@ namespace TAO_PEGTL_NAMESPACE::internal using data_t = typename R::type; using pair_t = input_pair< data_t >; - static constexpr std::size_t min_input_size = sizeof( data_t ); - static constexpr std::size_t max_input_size = sizeof( data_t ); - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ ) noexcept + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( sizeof( data_t ) ) ) ) { + if( in.size( sizeof( data_t ) ) < sizeof( data_t ) ) { + return { 0, 0 }; + } const data_t data = R::read( in.current() ) & M; return { data, sizeof( data_t ) }; } diff --git a/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint8.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint8.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1d214fa100d3acb8e24a88446d266657ce658bb4 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint8.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT8_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT8_HPP + +#include <cstddef> +#include <cstdint> + +#include "../../config.hpp" +#include "../../internal/input_pair.hpp" + +namespace TAO_PEGTL_NAMESPACE::internal +{ + template< std::uint8_t M > + struct peek_mask_uint8 + { + using data_t = std::uint8_t; + using pair_t = input_pair< std::uint8_t >; + + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) ) + { + if( in.empty() ) { + return { 0, 0 }; + } + return { std::uint8_t( in.peek_uint8() & M ), 1 }; + } + }; + +} // namespace TAO_PEGTL_NAMESPACE::internal + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_uint.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint.hpp similarity index 64% rename from packages/PEGTL/include/tao/pegtl/internal/peek_uint.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint.hpp index 83b3eaad538b4d2bca7f10decba9266d0e51d3f4..cdd0cf43706829f7269ce7b4bbc76b1037df8f13 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_uint.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint.hpp @@ -1,15 +1,15 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_PEEK_UINT_HPP -#define TAO_PEGTL_INTERNAL_PEEK_UINT_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT_HPP #include <cstddef> #include <cstdint> -#include "../config.hpp" +#include "../../config.hpp" +#include "../../internal/input_pair.hpp" -#include "input_pair.hpp" #include "read_uint.hpp" namespace TAO_PEGTL_NAMESPACE::internal @@ -20,12 +20,12 @@ namespace TAO_PEGTL_NAMESPACE::internal using data_t = typename R::type; using pair_t = input_pair< data_t >; - static constexpr std::size_t min_input_size = sizeof( data_t ); - static constexpr std::size_t max_input_size = sizeof( data_t ); - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ ) noexcept + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( sizeof( data_t ) ) ) ) { + if( in.size( sizeof( data_t ) ) < sizeof( data_t ) ) { + return { 0, 0 }; + } const data_t data = R::read( in.current() ); return { data, sizeof( data_t ) }; } diff --git a/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint8.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint8.hpp new file mode 100644 index 0000000000000000000000000000000000000000..43010dda933ae454907b0f844366b713e14b962f --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint8.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT8_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT8_HPP + +#include <cstddef> +#include <cstdint> + +#include "../../config.hpp" +#include "../../internal/input_pair.hpp" + +namespace TAO_PEGTL_NAMESPACE::internal +{ + struct peek_uint8 + { + using data_t = std::uint8_t; + using pair_t = input_pair< std::uint8_t >; + + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) ) + { + if( in.empty() ) { + return { 0, 0 }; + } + return { in.peek_uint8(), 1 }; + } + }; + +} // namespace TAO_PEGTL_NAMESPACE::internal + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_utf16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf16.hpp similarity index 69% rename from packages/PEGTL/include/tao/pegtl/internal/peek_utf16.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf16.hpp index 4552c64f622b48671a187ed27768c9fa3e89f0d5..e52a87e256cb72365e76bb64a2eb4b4e5f320cea 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_utf16.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf16.hpp @@ -1,14 +1,14 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_PEEK_UTF16_HPP -#define TAO_PEGTL_INTERNAL_PEEK_UTF16_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF16_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF16_HPP #include <type_traits> -#include "../config.hpp" +#include "../../config.hpp" +#include "../../internal/input_pair.hpp" -#include "input_pair.hpp" #include "read_uint.hpp" namespace TAO_PEGTL_NAMESPACE::internal @@ -24,17 +24,17 @@ namespace TAO_PEGTL_NAMESPACE::internal static_assert( sizeof( short_t ) == 2 ); static_assert( sizeof( char16_t ) == 2 ); - static constexpr std::size_t min_input_size = 2; - static constexpr std::size_t max_input_size = 4; - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t s ) noexcept + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( 4 ) ) ) { + if( in.size( 2 ) < 2 ) { + return { 0, 0 }; + } const char32_t t = R::read( in.current() ); if( ( t < 0xd800 ) || ( t > 0xdfff ) ) { return { t, 2 }; } - if( ( t >= 0xdc00 ) || ( s < 4 ) ) { + if( ( t >= 0xdc00 ) || ( in.size( 4 ) < 4 ) ) { return { 0, 0 }; } const char32_t u = R::read( in.current() + 2 ); diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_utf32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf32.hpp similarity index 56% rename from packages/PEGTL/include/tao/pegtl/internal/peek_utf32.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf32.hpp index 293d38fbad569e7e9ba32e278ff2aa010d9af3e2..19958a0fa7fdb90871417e04681309101411e25f 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_utf32.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf32.hpp @@ -1,14 +1,14 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_PEEK_UTF32_HPP -#define TAO_PEGTL_INTERNAL_PEEK_UTF32_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF32_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF32_HPP #include <cstddef> -#include "../config.hpp" +#include "../../config.hpp" +#include "../../internal/input_pair.hpp" -#include "input_pair.hpp" #include "read_uint.hpp" namespace TAO_PEGTL_NAMESPACE::internal @@ -21,14 +21,14 @@ namespace TAO_PEGTL_NAMESPACE::internal static_assert( sizeof( char32_t ) == 4 ); - static constexpr std::size_t min_input_size = 4; - static constexpr std::size_t max_input_size = 4; - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ ) noexcept + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( 4 ) ) ) { + if( in.size( 4 ) < 4 ) { + return { 0, 0 }; + } const char32_t t = R::read( in.current() ); - if( ( 0 <= t ) && ( t <= 0x10ffff ) && !( t >= 0xd800 && t <= 0xdfff ) ) { + if( ( t <= 0x10ffff ) && !( t >= 0xd800 && t <= 0xdfff ) ) { return { t, 4 }; } return { 0, 0 }; diff --git a/packages/PEGTL/include/tao/pegtl/internal/read_uint.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/read_uint.hpp similarity index 88% rename from packages/PEGTL/include/tao/pegtl/internal/read_uint.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/internal/read_uint.hpp index 96fbcc73da4973c48c1091cc48e98ca44eaeea64..bf102357642d100387af5d83075abcb4fa10e338 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/read_uint.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/read_uint.hpp @@ -1,12 +1,12 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_READ_UINT_HPP -#define TAO_PEGTL_INTERNAL_READ_UINT_HPP +#ifndef TAO_PEGTL_CONTRIB_INTERNAL_READ_UINT_HPP +#define TAO_PEGTL_CONTRIB_INTERNAL_READ_UINT_HPP #include <cstdint> -#include "../config.hpp" +#include "../../config.hpp" #include "endian.hpp" diff --git a/packages/PEGTL/include/tao/pegtl/contrib/json.hpp b/packages/PEGTL/include/tao/pegtl/contrib/json.hpp index 76564b5ef991f9a8cc788784f58a1e05fec5918e..5ae8326efb6cf8800d5dbf3845f7f6ca2cb437a2 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/json.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/json.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_JSON_HPP @@ -9,8 +9,6 @@ #include "../rules.hpp" #include "../utf8.hpp" -#include "abnf.hpp" - namespace TAO_PEGTL_NAMESPACE::json { // JSON grammar according to RFC 8259 @@ -28,22 +26,22 @@ namespace TAO_PEGTL_NAMESPACE::json struct name_separator : pad< one< ':' >, ws > {}; struct value_separator : padr< one< ',' > > {}; - struct false_ : string< 'f', 'a', 'l', 's', 'e' > {}; + struct false_ : string< 'f', 'a', 'l', 's', 'e' > {}; // NOLINT(readability-identifier-naming) struct null : string< 'n', 'u', 'l', 'l' > {}; - struct true_ : string< 't', 'r', 'u', 'e' > {}; + struct true_ : string< 't', 'r', 'u', 'e' > {}; // NOLINT(readability-identifier-naming) - struct digits : plus< abnf::DIGIT > {}; + struct digits : plus< digit > {}; struct exp : seq< one< 'e', 'E' >, opt< one< '-', '+'> >, must< digits > > {}; struct frac : if_must< one< '.' >, digits > {}; - struct int_ : sor< one< '0' >, digits > {}; + struct int_ : sor< one< '0' >, digits > {}; // NOLINT(readability-identifier-naming) struct number : seq< opt< one< '-' > >, int_, opt< frac >, opt< exp > > {}; - struct xdigit : abnf::HEXDIG {}; + struct xdigit : pegtl::xdigit {}; struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {}; struct escaped_char : one< '"', '\\', '/', 'b', 'f', 'n', 'r', 't' > {}; struct escaped : sor< escaped_char, unicode > {}; struct unescaped : utf8::range< 0x20, 0x10FFFF > {}; - struct char_ : if_then_else< one< '\\' >, must< escaped >, unescaped > {}; + struct char_ : if_then_else< one< '\\' >, must< escaped >, unescaped > {}; // NOLINT(readability-identifier-naming) struct string_content : until< at< one< '"' > >, must< char_ > > {}; struct string : seq< one< '"' >, must< string_content >, any > diff --git a/packages/PEGTL/include/tao/pegtl/contrib/json_pointer.hpp b/packages/PEGTL/include/tao/pegtl/contrib/json_pointer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9732f705edfa33190447afbd5dc0db64b983ce78 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/json_pointer.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_JSON_POINTER_HPP +#define TAO_PEGTL_CONTRIB_JSON_POINTER_HPP + +#include "../ascii.hpp" +#include "../config.hpp" +#include "../rules.hpp" +#include "../utf8.hpp" + +namespace TAO_PEGTL_NAMESPACE::json_pointer +{ + // JSON pointer grammar according to RFC 6901 + + // clang-format off + struct unescaped : utf8::ranges< 0x0, 0x2E, 0x30, 0x7D, 0x7F, 0x10FFFF > {}; + struct escaped : seq< one< '~' >, one< '0', '1' > > {}; + + struct reference_token : star< sor< unescaped, escaped > > {}; + struct json_pointer : star< one< '/' >, reference_token > {}; + // clang-format on + + // relative JSON pointer, see ... + + // clang-format off + struct non_negative_integer : sor< one< '0' >, plus< digit > > {}; + struct relative_json_pointer : seq< non_negative_integer, sor< one< '#' >, json_pointer > > {}; + // clang-format on + +} // namespace TAO_PEGTL_NAMESPACE::json_pointer + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp index 61182d770a8748e438a0f033c647c18eb29cb809..964fdf6f0ec8ef74e98c58cc29d87d69c44eb4ee 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_PARSE_TREE_HPP @@ -14,16 +14,21 @@ #include <utility> #include <vector> +#include "remove_first_state.hpp" +#include "shuffle_states.hpp" + +#include "../apply_mode.hpp" #include "../config.hpp" #include "../memory_input.hpp" #include "../normal.hpp" #include "../nothing.hpp" #include "../parse.hpp" +#include "../rewind_mode.hpp" -#include "../analysis/counted.hpp" -#include "../analysis/generic.hpp" #include "../internal/demangle.hpp" +#include "../internal/enable_control.hpp" #include "../internal/iterator.hpp" +#include "../internal/try_catch_type.hpp" namespace TAO_PEGTL_NAMESPACE::parse_tree { @@ -34,7 +39,7 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree using children_t = std::vector< std::unique_ptr< node_t > >; children_t children; - std::type_index id = typeid( void ); + std::string_view type; std::string source; TAO_PEGTL_NAMESPACE::internal::iterator m_begin; @@ -56,19 +61,19 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree [[nodiscard]] bool is_root() const noexcept { - return id == typeid( void ); + return type.empty(); } template< typename U > - [[nodiscard]] bool is() const noexcept + [[nodiscard]] bool is_type() const noexcept { - return id == typeid( U ); + return type == TAO_PEGTL_NAMESPACE::internal::demangle< U >(); } - [[nodiscard]] std::string name() const + template< typename U > + void set_type() noexcept { - assert( !is_root() ); - return TAO_PEGTL_NAMESPACE::internal::demangle( id.name() ); + type = TAO_PEGTL_NAMESPACE::internal::demangle< U >(); } [[nodiscard]] position begin() const @@ -112,26 +117,25 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree } // all non-root nodes are initialized by calling this method - template< typename Rule, typename Input, typename... States > - void start( const Input& in, States&&... /*unused*/ ) + template< typename Rule, typename ParseInput, typename... States > + void start( const ParseInput& in, States&&... /*unused*/ ) { - id = typeid( Rule ); + set_type< Rule >(); source = in.source(); m_begin = TAO_PEGTL_NAMESPACE::internal::iterator( in.iterator() ); } // if parsing of the rule succeeded, this method is called - template< typename Rule, typename Input, typename... States > - void success( const Input& in, States&&... /*unused*/ ) noexcept + template< typename Rule, typename ParseInput, typename... States > + void success( const ParseInput& in, States&&... /*unused*/ ) noexcept { m_end = TAO_PEGTL_NAMESPACE::internal::iterator( in.iterator() ); } // if parsing of the rule failed, this method is called - template< typename Rule, typename Input, typename... States > - void failure( const Input& /*unused*/, States&&... /*unused*/ ) noexcept - { - } + template< typename Rule, typename ParseInput, typename... States > + void failure( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept + {} // if parsing succeeded and the (optional) transform call // did not discard the node, it is appended to its parent. @@ -147,11 +151,16 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree struct node : basic_node< node > - { - }; + {}; namespace internal { + template< typename > + inline constexpr bool is_try_catch_type = false; + + template< typename Exception, typename... Rules > + inline constexpr bool is_try_catch_type< TAO_PEGTL_NAMESPACE::internal::try_catch_type< Exception, Rules... > > = true; + template< typename Node > struct state { @@ -182,154 +191,36 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree template< typename Selector, typename... Parameters > void transform( Parameters&&... /*unused*/ ) noexcept + {} + + template< typename Selector, typename ParseInput, typename Node, typename... States > + auto transform( const ParseInput& in, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( in, n, st... ) ) ) + -> decltype( Selector::transform( in, n, st... ), void() ) { + Selector::transform( in, n, st... ); } - // this one, if applicable, is more specialized than the above - template< typename Selector, typename Node, typename... States > - auto transform( std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( n, st... ) ) ) + template< typename Selector, typename ParseInput, typename Node, typename... States > + auto transform( const ParseInput& /*unused*/, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( n, st... ) ) ) -> decltype( Selector::transform( n, st... ), void() ) { Selector::transform( n, st... ); } - template< unsigned Level, typename Analyse, template< typename... > class Selector > - struct is_leaf - : std::false_type - { - }; - - template< analysis::rule_type Type, template< typename... > class Selector > - struct is_leaf< 0, analysis::generic< Type >, Selector > - : std::true_type - { - }; + template< typename Rule, template< typename... > class Selector > + inline constexpr bool is_selected_node = ( TAO_PEGTL_NAMESPACE::internal::enable_control< Rule > && Selector< Rule >::value ); - template< analysis::rule_type Type, unsigned Count, template< typename... > class Selector > - struct is_leaf< 0, analysis::counted< Type, Count >, Selector > - : std::true_type - { - }; - - template< analysis::rule_type Type, typename... Rules, template< typename... > class Selector > - struct is_leaf< 0, analysis::generic< Type, Rules... >, Selector > - : std::false_type - { - }; + template< unsigned Level, typename Subs, template< typename... > class Selector > + inline constexpr bool is_leaf{}; - template< analysis::rule_type Type, unsigned Count, typename... Rules, template< typename... > class Selector > - struct is_leaf< 0, analysis::counted< Type, Count, Rules... >, Selector > - : std::false_type - { - }; + template< typename... Rules, template< typename... > class Selector > + inline constexpr bool is_leaf< 0, type_list< Rules... >, Selector > = ( sizeof...( Rules ) == 0 ); template< unsigned Level, typename Rule, template< typename... > class Selector > - inline constexpr bool is_unselected_leaf = !Selector< Rule >::value && is_leaf< Level, typename Rule::analyze_t, Selector >::value; + inline constexpr bool is_unselected_branch = ( !is_selected_node< Rule, Selector > && is_leaf< Level, typename Rule::subs_t, Selector > ); - template< unsigned Level, analysis::rule_type Type, typename... Rules, template< typename... > class Selector > - struct is_leaf< Level, analysis::generic< Type, Rules... >, Selector > - : std::bool_constant< ( is_unselected_leaf< Level - 1, Rules, Selector > && ... ) > - { - }; - - template< unsigned Level, analysis::rule_type Type, unsigned Count, typename... Rules, template< typename... > class Selector > - struct is_leaf< Level, analysis::counted< Type, Count, Rules... >, Selector > - : std::bool_constant< ( is_unselected_leaf< Level - 1, Rules, Selector > && ... ) > - { - }; - - template< typename T > - struct control - { - template< typename Input, typename Tuple, std::size_t... Is > - static void start_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::start( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ) ) ) - { - T::start( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ); - } - - template< typename Input, typename... States > - static void start( const Input& in, States&&... st ) noexcept( noexcept( start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) ) - { - start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ); - } - - template< typename Input, typename Tuple, std::size_t... Is > - static void success_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::success( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ) ) ) - { - T::success( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ); - } - - template< typename Input, typename... States > - static void success( const Input& in, States&&... st ) noexcept( noexcept( success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) ) - { - success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ); - } - - template< typename Input, typename Tuple, std::size_t... Is > - static void failure_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::failure( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ) ) ) - { - T::failure( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ); - } - - template< typename Input, typename... States > - static void failure( const Input& in, States&&... st ) noexcept( noexcept( failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) ) - { - failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ); - } - - template< typename Input, typename Tuple, std::size_t... Is > - static void raise_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::raise( in, std::get< Is >( t )... ) ) ) - { - T::raise( in, std::get< Is >( t )... ); - } - - template< typename Input, typename... States > - static void raise( const Input& in, States&&... st ) noexcept( noexcept( raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) ) - { - raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ); - } - - template< template< typename... > class Action, typename Iterator, typename Input, typename Tuple, std::size_t... Is > - static auto apply_impl( const Iterator& begin, const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::template apply< Action >( begin, in, std::get< Is >( t )... ) ) ) - -> decltype( T::template apply< Action >( begin, in, std::get< Is >( t )... ) ) - { - return T::template apply< Action >( begin, in, std::get< Is >( t )... ); - } - - template< template< typename... > class Action, typename Iterator, typename Input, typename... States > - static auto apply( const Iterator& begin, const Input& in, States&&... st ) noexcept( noexcept( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) ) - -> decltype( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) - { - return apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ); - } - - template< template< typename... > class Action, typename Input, typename Tuple, std::size_t... Is > - static auto apply0_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::template apply0< Action >( in, std::get< Is >( t )... ) ) ) - -> decltype( T::template apply0< Action >( in, std::get< Is >( t )... ) ) - { - return T::template apply0< Action >( in, std::get< Is >( t )... ); - } - - template< template< typename... > class Action, typename Input, typename... States > - static auto apply0( const Input& in, States&&... st ) noexcept( noexcept( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) ) - -> decltype( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) - { - return apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ); - } - - template< apply_mode A, - rewind_mode M, - template< typename... > - class Action, - template< typename... > - class Control, - typename Input, - typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) - { - return T::template match< A, M, Action, Control >( in, st... ); - } - }; + template< unsigned Level, typename... Rules, template< typename... > class Selector > + inline constexpr bool is_leaf< Level, type_list< Rules... >, Selector > = ( is_unselected_branch< Level - 1, Rules, Selector > && ... ); template< typename Node, template< typename... > class Selector, template< typename... > class Control > struct make_control @@ -338,92 +229,90 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree struct state_handler; template< typename Rule > - using type = control< state_handler< Rule, Selector< Rule >::value, is_leaf< 8, typename Rule::analyze_t, Selector >::value > >; + using type = rotate_states_right< state_handler< Rule, is_selected_node< Rule, Selector >, is_leaf< 8, typename Rule::subs_t, Selector > > >; }; template< typename Node, template< typename... > class Selector, template< typename... > class Control > template< typename Rule > struct make_control< Node, Selector, Control >::state_handler< Rule, false, true > - : Control< Rule > - { - template< typename Input, typename... States > - static void start( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::start( in, st... ) ) ) - { - Control< Rule >::start( in, st... ); - } - - template< typename Input, typename... States > - static void success( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::success( in, st... ) ) ) - { - Control< Rule >::success( in, st... ); - } - - template< typename Input, typename... States > - static void failure( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) ) - { - Control< Rule >::failure( in, st... ); - } - }; + : remove_first_state< Control< Rule > > + {}; template< typename Node, template< typename... > class Selector, template< typename... > class Control > template< typename Rule > struct make_control< Node, Selector, Control >::state_handler< Rule, false, false > - : Control< Rule > + : remove_first_state< Control< Rule > > { - template< typename Input, typename... States > - static void start( const Input& in, state< Node >& state, States&&... st ) - { - Control< Rule >::start( in, st... ); - state.emplace_back(); - } - - template< typename Input, typename... States > - static void success( const Input& in, state< Node >& state, States&&... st ) + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control2, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - Control< Rule >::success( in, st... ); - auto n = std::move( state.back() ); - state.pop_back(); - for( auto& c : n->children ) { - state.back()->children.emplace_back( std::move( c ) ); + auto& state = std::get< sizeof...( st ) - 1 >( std::tie( st... ) ); + if constexpr( is_try_catch_type< Rule > ) { + internal::state< Node > tmp; + tmp.emplace_back(); + tmp.stack.swap( state.stack ); + const bool result = Control< Rule >::template match< A, M, Action, Control2 >( in, st... ); + tmp.stack.swap( state.stack ); + if( result ) { + for( auto& c : tmp.back()->children ) { + state.back()->children.emplace_back( std::move( c ) ); + } + } + return result; + } + else { + state.emplace_back(); + const bool result = Control< Rule >::template match< A, M, Action, Control2 >( in, st... ); + if( result ) { + auto n = std::move( state.back() ); + state.pop_back(); + for( auto& c : n->children ) { + state.back()->children.emplace_back( std::move( c ) ); + } + } + else { + state.pop_back(); + } + return result; } - } - - template< typename Input, typename... States > - static void failure( const Input& in, state< Node >& state, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) ) - { - Control< Rule >::failure( in, st... ); - state.pop_back(); } }; template< typename Node, template< typename... > class Selector, template< typename... > class Control > template< typename Rule, bool B > struct make_control< Node, Selector, Control >::state_handler< Rule, true, B > - : Control< Rule > + : remove_first_state< Control< Rule > > { - template< typename Input, typename... States > - static void start( const Input& in, state< Node >& state, States&&... st ) + template< typename ParseInput, typename... States > + static void start( const ParseInput& in, state< Node >& state, States&&... st ) { Control< Rule >::start( in, st... ); state.emplace_back(); state.back()->template start< Rule >( in, st... ); } - template< typename Input, typename... States > - static void success( const Input& in, state< Node >& state, States&&... st ) + template< typename ParseInput, typename... States > + static void success( const ParseInput& in, state< Node >& state, States&&... st ) { Control< Rule >::success( in, st... ); auto n = std::move( state.back() ); state.pop_back(); n->template success< Rule >( in, st... ); - transform< Selector< Rule > >( n, st... ); + transform< Selector< Rule > >( in, n, st... ); if( n ) { state.back()->emplace_back( std::move( n ), st... ); } } - template< typename Input, typename... States > - static void failure( const Input& in, state< Node >& state, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) && noexcept( std::declval< Node& >().template failure< Rule >( in, st... ) ) ) + template< typename ParseInput, typename... States > + static void failure( const ParseInput& in, state< Node >& state, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) && noexcept( std::declval< Node& >().template failure< Rule >( in, st... ) ) ) { Control< Rule >::failure( in, st... ); state.back()->template failure< Rule >( in, st... ); @@ -527,9 +416,9 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree template< typename... > class Selector = internal::store_all, template< typename... > class Action = nothing, template< typename... > class Control = normal, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] std::unique_ptr< Node > parse( Input&& in, States&&... st ) + [[nodiscard]] std::unique_ptr< Node > parse( ParseInput&& in, States&&... st ) { internal::state< Node > state; if( !TAO_PEGTL_NAMESPACE::parse< Rule, Action, internal::make_control< Node, Selector, Control >::template type >( in, st..., state ) ) { @@ -543,9 +432,9 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree template< typename... > class Selector = internal::store_all, template< typename... > class Action = nothing, template< typename... > class Control = normal, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] std::unique_ptr< node > parse( Input&& in, States&&... st ) + [[nodiscard]] std::unique_ptr< node > parse( ParseInput&& in, States&&... st ) { return parse< Rule, node, Selector, Action, Control >( in, st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp index e9f15892f44925b11921313313f1498bfb8f1b91..a16b171d5eedbee9d38f918ee3c9d8c2209c91ab 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_PARSE_TREE_TO_DOT_HPP @@ -14,32 +14,89 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree { namespace internal { - void print_dot_node( std::ostream& os, const parse_tree::node& n, const std::string& s ) + inline void escape( std::ostream& os, const std::string_view s ) { - if( n.has_content() ) { - os << " x" << &n << " [ label=\"" << s << "\\n\\\"" << n.string_view() << "\\\"\" ]\n"; + static const char* h = "0123456789abcdef"; + + const char* p = s.data(); + const char* l = p; + const char* const e = s.data() + s.size(); + while( p != e ) { + const unsigned char c = *p; + if( c == '\\' ) { + os.write( l, p - l ); + l = ++p; + os << "\\\\\\\\"; + } + else if( c == '"' ) { + os.write( l, p - l ); + l = ++p; + os << "\\\\\\\""; + } + else if( c < 32 ) { + os.write( l, p - l ); + l = ++p; + switch( c ) { + case '\b': + os << "\\\\b"; + break; + case '\f': + os << "\\\\f"; + break; + case '\n': + os << "\\\\n"; + break; + case '\r': + os << "\\\\r"; + break; + case '\t': + os << "\\\\t"; + break; + default: + os << "\\\\u00" << h[ ( c & 0xf0 ) >> 4 ] << h[ c & 0x0f ]; + } + } + else if( c == 127 ) { + os.write( l, p - l ); + l = ++p; + os << "\\\\u007f"; + } + else { + ++p; + } } - else { - os << " x" << &n << " [ label=\"" << s << "\" ]\n"; + os.write( l, p - l ); + } + + template< typename Node > + void print_dot_node( std::ostream& os, const Node& n, const std::string_view s ) + { + os << " x" << &n << " [ label=\""; + escape( os, s ); + if( n.has_content() ) { + os << "\\n\\\""; + escape( os, n.string_view() ); + os << "\\\""; } + os << "\" ]\n"; if( !n.children.empty() ) { os << " x" << &n << " -> { "; for( auto& up : n.children ) { os << "x" << up.get() << ( ( up == n.children.back() ) ? " }\n" : ", " ); } for( auto& up : n.children ) { - print_dot_node( os, *up, up->name() ); + print_dot_node( os, *up, up->type ); } } } } // namespace internal - void print_dot( std::ostream& os, const parse_tree::node& n ) + template< typename Node > + void print_dot( std::ostream& os, const Node& n ) { - assert( n.is_root() ); os << "digraph parse_tree\n{\n"; - internal::print_dot_node( os, n, "ROOT" ); + internal::print_dot_node( os, n, n.is_root() ? "ROOT" : n.type ); os << "}\n"; } diff --git a/packages/PEGTL/include/tao/pegtl/contrib/print.hpp b/packages/PEGTL/include/tao/pegtl/contrib/print.hpp new file mode 100644 index 0000000000000000000000000000000000000000..96c1792fe91d6798ea9b2ed267c3ccdc33c7d57c --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/print.hpp @@ -0,0 +1,75 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_PRINT_HPP +#define TAO_PEGTL_CONTRIB_PRINT_HPP + +#include <ostream> + +#include "../config.hpp" +#include "../visit.hpp" + +#include "../internal/demangle.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + template< typename Name > + struct print_rules + { + static void visit( std::ostream& os ) + { + os << demangle< Name >() << '\n'; + } + }; + + template< typename Name > + struct print_sub_rules + { + static void visit( std::ostream& os ) + { + const auto first = demangle< Name >(); + os << first << '\n'; + + const auto second = demangle< typename Name::rule_t >(); + if( first != second ) { + os << " (aka) " << second << '\n'; + } + + print_subs( os, typename Name::subs_t() ); + + os << '\n'; + } + + private: + template< typename... Rules > + static void print_subs( std::ostream& os, type_list< Rules... > /*unused*/ ) + { + ( print_sub< Rules >( os ), ... ); + } + + template< typename Rule > + static void print_sub( std::ostream& os ) + { + os << " (sub) " << demangle< Rule >() << '\n'; + } + }; + + } // namespace internal + + template< typename Grammar > + void print_rules( std::ostream& os ) + { + visit< Grammar, internal::print_rules >( os ); + } + + template< typename Grammar > + void print_sub_rules( std::ostream& os ) + { + visit< Grammar, internal::print_sub_rules >( os ); + } + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp b/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0c49af45e70214c29d2fd7d1b48f489d96d3e9c7 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp @@ -0,0 +1,59 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_PRINT_COVERAGE_HPP +#define TAO_PEGTL_CONTRIB_PRINT_COVERAGE_HPP + +#include <ostream> + +#include "coverage.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + // output is JSON + inline void print_coverage( std::ostream& os, const coverage_state& state ) + { + os << "{\n" + << " \"grammar\": \"" << state.grammar << "\",\n" + << " \"source\": \"" << state.source << "\",\n" + << " \"result\": " << ( state.result ? "true" : "false" ) << ",\n" + << " \"coverage\":\n" + << " [\n"; + bool f = true; + for( const auto& [ k, v ] : state.map ) { + if( f ) { + f = false; + } + else { + os << ",\n"; + } + os << " {\n" + << " \"rule\": \"" << k << "\",\n" + << " \"start\": " << v.start << ", \"success\": " << v.success << ", \"local_failure\": " << v.local_failure << ", \"global_failure\": " << v.global_failure << ", \"raise\": " << v.raise << ",\n"; + if( v.branches.empty() ) { + os << " \"branches\": []\n"; + } + else { + os << " \"branches\": [\n"; + bool f2 = true; + for( const auto& [ k2, v2 ] : v.branches ) { + if( f2 ) { + f2 = false; + } + else { + os << ",\n"; + } + os << " { \"branch\": \"" << k2 << "\", \"start\": " << v2.start << ", \"success\": " << v2.success << ", \"local_failure\": " << v2.local_failure << ", \"global_failure\": " << v2.global_failure << ", \"raise\": " << v2.raise << " }"; + } + os << "\n ]\n"; + } + os << " }"; + } + os << "\n" + << " ]\n" + << "}\n"; + } + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp index 968ebc791b1ee8579c88c23c86f29f32cab34f9c..7fc2e049bd994aa7ceb44a2e7bccb775c3d48331 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_RAW_STRING_HPP @@ -8,19 +8,20 @@ #include <type_traits> #include "../apply_mode.hpp" +#include "../ascii.hpp" #include "../config.hpp" #include "../rewind_mode.hpp" #include "../internal/bytes.hpp" +#include "../internal/enable_control.hpp" #include "../internal/eof.hpp" #include "../internal/eol.hpp" #include "../internal/must.hpp" #include "../internal/not_at.hpp" #include "../internal/seq.hpp" -#include "../internal/skip_control.hpp" #include "../internal/star.hpp" -#include "../analysis/generic.hpp" +#include "analyze_traits.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -29,7 +30,8 @@ namespace TAO_PEGTL_NAMESPACE template< char Open, char Marker > struct raw_string_open { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = raw_string_open; + using subs_t = empty_list; template< apply_mode A, rewind_mode, @@ -37,9 +39,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) ) + [[nodiscard]] static bool match( ParseInput& in, std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) ) { if( in.empty() || ( in.peek_char( 0 ) != Open ) ) { return false; @@ -62,12 +64,13 @@ namespace TAO_PEGTL_NAMESPACE }; template< char Open, char Marker > - inline constexpr bool skip_control< raw_string_open< Open, Marker > > = true; + inline constexpr bool enable_control< raw_string_open< Open, Marker > > = false; template< char Marker, char Close > struct at_raw_string_close { - using analyze_t = analysis::generic< analysis::rule_type::opt >; + using rule_t = at_raw_string_close; + using subs_t = empty_list; template< apply_mode A, rewind_mode, @@ -75,9 +78,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, const std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) ) + [[nodiscard]] static bool match( ParseInput& in, const std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) ) { if( in.size( marker_size ) < marker_size ) { return false; @@ -98,15 +101,18 @@ namespace TAO_PEGTL_NAMESPACE }; template< char Marker, char Close > - inline constexpr bool skip_control< at_raw_string_close< Marker, Close > > = true; + inline constexpr bool enable_control< at_raw_string_close< Marker, Close > > = false; template< typename Cond, typename... Rules > - struct raw_string_until; + struct raw_string_until + : raw_string_until< Cond, seq< Rules... > > + {}; template< typename Cond > struct raw_string_until< Cond > { - using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, bytes< 1 > >, Cond >; + using rule_t = raw_string_until; + using subs_t = type_list< Cond >; template< apply_mode A, rewind_mode M, @@ -114,9 +120,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, const std::size_t& marker_size, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, const std::size_t& marker_size, States&&... st ) { auto m = in.template mark< M >(); @@ -130,10 +136,11 @@ namespace TAO_PEGTL_NAMESPACE } }; - template< typename Cond, typename... Rules > - struct raw_string_until + template< typename Cond, typename Rule > + struct raw_string_until< Cond, Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, Rules... >, Cond >; + using rule_t = raw_string_until; + using subs_t = type_list< Cond, Rule >; template< apply_mode A, rewind_mode M, @@ -141,15 +148,15 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, const std::size_t& marker_size, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, const std::size_t& marker_size, States&&... st ) { auto m = in.template mark< M >(); using m_t = decltype( m ); while( !Control< Cond >::template match< A, rewind_mode::required, Action, Control >( in, marker_size, st... ) ) { - if( in.empty() || !( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) ) { + if( !Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ) { return false; } } @@ -158,7 +165,7 @@ namespace TAO_PEGTL_NAMESPACE }; template< typename Cond, typename... Rules > - inline constexpr bool skip_control< raw_string_until< Cond, Rules... > > = true; + inline constexpr bool enable_control< raw_string_until< Cond, Rules... > > = false; } // namespace internal @@ -194,10 +201,10 @@ namespace TAO_PEGTL_NAMESPACE // when a raw string is not closed properly or has invalid content. struct content : internal::raw_string_until< internal::at_raw_string_close< Marker, Close >, Contents... > - { - }; + {}; - using analyze_t = typename internal::seq< internal::bytes< 1 >, content, internal::bytes< 1 > >::analyze_t; + using rule_t = raw_string; + using subs_t = type_list< internal::raw_string_open< Open, Marker >, internal::must< content > >; template< apply_mode A, rewind_mode M, @@ -205,14 +212,14 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { std::size_t marker_size; - if( internal::raw_string_open< Open, Marker >::template match< A, M, Action, Control >( in, marker_size, st... ) ) { + if( Control< internal::raw_string_open< Open, Marker > >::template match< A, M, Action, Control >( in, marker_size, st... ) ) { // TODO: Do not rely on must<> - (void)internal::must< content >::template match< A, M, Action, Control >( in, marker_size, st... ); + (void)Control< internal::must< content > >::template match< A, M, Action, Control >( in, marker_size, st... ); in.bump_in_this_line( marker_size ); return true; } @@ -220,6 +227,16 @@ namespace TAO_PEGTL_NAMESPACE } }; + template< typename Name, char Open, char Marker, char Close > + struct analyze_traits< Name, raw_string< Open, Marker, Close > > + : analyze_any_traits<> + {}; + + template< typename Name, char Open, char Marker, char Close, typename... Contents > + struct analyze_traits< Name, raw_string< Open, Marker, Close, Contents... > > + : analyze_traits< Name, typename seq< any, star< Contents... >, any >::rule_t > + {}; + } // namespace TAO_PEGTL_NAMESPACE #endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp b/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp new file mode 100644 index 0000000000000000000000000000000000000000..48030def2e9bb687e86783ce0558029fd43ad96c --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp @@ -0,0 +1,58 @@ +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_REMOVE_FIRST_STATE_HPP +#define TAO_PEGTL_CONTRIB_REMOVE_FIRST_STATE_HPP + +#include "../config.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + // Applies to start(), success(), failure(), raise(), apply(), and apply0(): + // The first state is removed when the call is forwarded to Base. + template< typename Base > + struct remove_first_state + : Base + { + template< typename ParseInput, typename State, typename... States > + static void start( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::start( in, st... ) ) ) + { + Base::start( in, st... ); + } + + template< typename ParseInput, typename State, typename... States > + static void success( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::success( in, st... ) ) ) + { + Base::success( in, st... ); + } + + template< typename ParseInput, typename State, typename... States > + static void failure( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::failure( in, st... ) ) ) + { + Base::failure( in, st... ); + } + + template< typename ParseInput, typename State, typename... States > + [[noreturn]] static void raise( const ParseInput& in, State&& /*unused*/, States&&... st ) + { + Base::raise( in, st... ); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename State, typename... States > + static auto apply( const Iterator& begin, const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::template apply< Action >( begin, in, st... ) ) ) + -> decltype( Base::template apply< Action >( begin, in, st... ) ) + { + return Base::template apply< Action >( begin, in, st... ); + } + + template< template< typename... > class Action, typename ParseInput, typename State, typename... States > + static auto apply0( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::template apply0< Action >( in, st... ) ) ) + -> decltype( Base::template apply0< Action >( in, st... ) ) + { + return Base::template apply0< Action >( in, st... ); + } + }; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp b/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5fb778b7dbb4d45c29107e987697bc5393b75658 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp @@ -0,0 +1,101 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_REMOVE_LAST_STATES_HPP +#define TAO_PEGTL_CONTRIB_REMOVE_LAST_STATES_HPP + +#include <tuple> +#include <utility> + +#include "../config.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + // Remove the last N states of start(), success(), failure(), raise(), apply(), and apply0() + template< typename Base, std::size_t N > + struct remove_last_states + : Base + { + template< typename ParseInput, typename Tuple, std::size_t... Is > + static void start_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::start( in, std::get< Is >( t )... ) ) ) + { + Base::start( in, std::get< Is >( t )... ); + } + + template< typename ParseInput, typename... States > + static void start( const ParseInput& in, States&&... st ) noexcept( noexcept( start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) ) + { + start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ); + } + + template< typename ParseInput, typename Tuple, std::size_t... Is > + static void success_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::success( in, std::get< Is >( t )... ) ) ) + { + Base::success( in, std::get< Is >( t )... ); + } + + template< typename ParseInput, typename... States > + static void success( const ParseInput& in, States&&... st ) noexcept( noexcept( success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) ) + { + success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ); + } + + template< typename ParseInput, typename Tuple, std::size_t... Is > + static void failure_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::failure( in, std::get< Is >( t )... ) ) ) + { + Base::failure( in, std::get< Is >( t )... ); + } + + template< typename ParseInput, typename... States > + static void failure( const ParseInput& in, States&&... st ) noexcept( noexcept( failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) ) + { + failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ); + } + + template< typename ParseInput, typename Tuple, std::size_t... Is > + [[noreturn]] static void raise_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) + { + Base::raise( in, std::get< Is >( t )... ); + } + + template< typename ParseInput, typename... States > + [[noreturn]] static void raise( const ParseInput& in, States&&... st ) + { + raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename Tuple, std::size_t... Is > + static auto apply_impl( const Iterator& begin, const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply< Action >( begin, in, std::get< Is >( t )... ) ) ) + -> decltype( Base::template apply< Action >( begin, in, std::get< Is >( t )... ) ) + { + return Base::template apply< Action >( begin, in, std::get< Is >( t )... ); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States > + static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) noexcept( noexcept( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) ) + -> decltype( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) + { + return apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ); + } + + template< template< typename... > class Action, typename ParseInput, typename Tuple, std::size_t... Is > + static auto apply0_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply0< Action >( in, std::get< Is >( t )... ) ) ) + -> decltype( Base::template apply0< Action >( in, std::get< Is >( t )... ) ) + { + return Base::template apply0< Action >( in, std::get< Is >( t )... ); + } + + template< template< typename... > class Action, typename ParseInput, typename... States > + static auto apply0( const ParseInput& in, States&&... st ) noexcept( noexcept( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) ) + -> decltype( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) + { + return apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ); + } + }; + + template< typename Base > + using remove_last_state = remove_last_states< Base, 1 >; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp b/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp index 3f85f5817616705b9a10629ea11c8ca004810586..7ec4639ef68c435f13d585b87a41fa8a5c7784e1 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp @@ -1,17 +1,21 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_REP_ONE_MIN_MAX_HPP #define TAO_PEGTL_CONTRIB_REP_ONE_MIN_MAX_HPP #include <algorithm> +#include <type_traits> #include "../config.hpp" - -#include "../analysis/counted.hpp" +#include "../type_list.hpp" #include "../internal/bump_help.hpp" -#include "../internal/skip_control.hpp" +#include "../internal/bytes.hpp" +#include "../internal/enable_control.hpp" +#include "../internal/opt.hpp" + +#include "analyze_traits.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -20,12 +24,13 @@ namespace TAO_PEGTL_NAMESPACE template< unsigned Min, unsigned Max, char C > struct rep_one_min_max { - using analyze_t = analysis::counted< analysis::rule_type::any, Min >; + using rule_t = rep_one_min_max; + using subs_t = empty_list; static_assert( Min <= Max ); - template< typename Input > - [[nodiscard]] static bool match( Input& in ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) { const auto size = in.size( Max + 1 ); if( size < Min ) { @@ -36,7 +41,7 @@ namespace TAO_PEGTL_NAMESPACE ++i; } if( ( Min <= i ) && ( i <= Max ) ) { - bump_help< result_on_found::success, Input, char, C >( in, i ); + bump_help< result_on_found::success, ParseInput, char, C >( in, i ); return true; } return false; @@ -44,19 +49,24 @@ namespace TAO_PEGTL_NAMESPACE }; template< unsigned Min, unsigned Max, char C > - inline constexpr bool skip_control< rep_one_min_max< Min, Max, C > > = true; + inline constexpr bool enable_control< rep_one_min_max< Min, Max, C > > = false; } // namespace internal inline namespace ascii { template< unsigned Min, unsigned Max, char C > - struct rep_one_min_max : internal::rep_one_min_max< Min, Max, C > - { - }; + struct rep_one_min_max + : internal::rep_one_min_max< Min, Max, C > + {}; } // namespace ascii + template< typename Name, unsigned Min, unsigned Max, char C > + struct analyze_traits< Name, internal::rep_one_min_max< Min, Max, C > > + : std::conditional_t< ( Min != 0 ), analyze_any_traits<>, analyze_opt_traits<> > + {}; + } // namespace TAO_PEGTL_NAMESPACE #endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/rep_string.hpp b/packages/PEGTL/include/tao/pegtl/contrib/rep_string.hpp index bd699ce8efd28b099d07b2d15373008842b64324..39796eef9816cc84c0594ad6d129b6001c3fa6f4 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/rep_string.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/rep_string.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_REP_STRING_HPP @@ -25,8 +25,7 @@ namespace TAO_PEGTL_NAMESPACE template< std::size_t N, char... Ss, char... Cs > struct make_rep_string< N, string< Ss... >, Cs... > : make_rep_string< N - 1, string< Ss..., Cs... >, Cs... > - { - }; + {}; } // namespace internal diff --git a/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp b/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e081051405ad231b944c5b2a14e5ddbfb25bef04 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp @@ -0,0 +1,169 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_SHUFFLE_STATES_HPP +#define TAO_PEGTL_CONTRIB_SHUFFLE_STATES_HPP + +#include <tuple> +#include <utility> + +#include "../config.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + template< std::size_t N > + struct rotate_left + { + template< std::size_t I, std::size_t S > + static constexpr std::size_t value = ( I + N ) % S; + }; + + template< std::size_t N > + struct rotate_right + { + template< std::size_t I, std::size_t S > + static constexpr std::size_t value = ( I + S - N ) % S; + }; + + struct reverse + { + template< std::size_t I, std::size_t S > + static constexpr std::size_t value = ( S - 1 ) - I; + }; + + } // namespace internal + + // Applies 'Shuffle' to the states of start(), success(), failure(), raise(), apply(), and apply0() + template< typename Base, typename Shuffle > + struct shuffle_states + : Base + { + template< typename ParseInput, typename Tuple, std::size_t... Is > + static void start_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::start( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) ) + { + Base::start( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ); + } + + template< typename ParseInput, typename... States > + static void start( const ParseInput& in, States&&... st ) noexcept( noexcept( start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) ) + { + start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ); + } + + template< typename ParseInput, typename State > + static void start( const ParseInput& in, State&& st ) noexcept( noexcept( Base::start( in, st ) ) ) + { + Base::start( in, st ); + } + + template< typename ParseInput, typename Tuple, std::size_t... Is > + static void success_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::success( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) ) + { + Base::success( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ); + } + + template< typename ParseInput, typename... States > + static void success( const ParseInput& in, States&&... st ) noexcept( noexcept( success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) ) + { + success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ); + } + + template< typename ParseInput, typename State > + static void success( const ParseInput& in, State&& st ) noexcept( noexcept( Base::success( in, st ) ) ) + { + Base::success( in, st ); + } + + template< typename ParseInput, typename Tuple, std::size_t... Is > + static void failure_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::failure( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) ) + { + Base::failure( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ); + } + + template< typename ParseInput, typename... States > + static void failure( const ParseInput& in, States&&... st ) noexcept( noexcept( failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) ) + { + failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ); + } + + template< typename ParseInput, typename State > + static void failure( const ParseInput& in, State&& st ) noexcept( noexcept( Base::failure( in, st ) ) ) + { + Base::failure( in, st ); + } + + template< typename ParseInput, typename Tuple, std::size_t... Is > + [[noreturn]] static void raise_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) + { + Base::raise( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ); + } + + template< typename ParseInput, typename... States > + [[noreturn]] static void raise( const ParseInput& in, States&&... st ) + { + raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ); + } + + template< typename ParseInput, typename State > + [[noreturn]] static void raise( const ParseInput& in, State&& st ) + { + Base::raise( in, st ); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename Tuple, std::size_t... Is > + static auto apply_impl( const Iterator& begin, const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) ) + -> decltype( Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) + { + return Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States > + static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) noexcept( noexcept( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) ) + -> decltype( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) + { + return apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename State > + static auto apply( const Iterator& begin, const ParseInput& in, State&& st ) noexcept( noexcept( Base::template apply< Action >( begin, in, st ) ) ) + -> decltype( Base::template apply< Action >( begin, in, st ) ) + { + return Base::template apply< Action >( begin, in, st ); + } + + template< template< typename... > class Action, typename ParseInput, typename Tuple, std::size_t... Is > + static auto apply0_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply0< Action >( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) ) + -> decltype( Base::template apply0< Action >( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) + { + return Base::template apply0< Action >( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ); + } + + template< template< typename... > class Action, typename ParseInput, typename... States > + static auto apply0( const ParseInput& in, States&&... st ) noexcept( noexcept( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) ) + -> decltype( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) + { + return apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ); + } + + template< template< typename... > class Action, typename ParseInput, typename State > + static auto apply0( const ParseInput& in, State&& st ) noexcept( noexcept( Base::template apply0< Action >( in, st ) ) ) + -> decltype( Base::template apply0< Action >( in, st ) ) + { + return Base::template apply0< Action >( in, st ); + } + }; + + template< typename Base, std::size_t N = 1 > + using rotate_states_left = shuffle_states< Base, internal::rotate_left< N > >; + + template< typename Base, std::size_t N = 1 > + using rotate_states_right = shuffle_states< Base, internal::rotate_right< N > >; + + template< typename Base > + using reverse_states = shuffle_states< Base, internal::reverse >; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/to_string.hpp b/packages/PEGTL/include/tao/pegtl/contrib/to_string.hpp index 122ad57f3e8b805cbcc9a86a84bd0302b1ca624a..5df1a2feae9b85e3263f13d9216c5c19a3398e94 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/to_string.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/to_string.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_TO_STRING_HPP @@ -20,7 +20,7 @@ namespace TAO_PEGTL_NAMESPACE { [[nodiscard]] static std::string get() { - const char s[] = { Cs..., 0 }; // NOLINT + const char s[] = { Cs..., 0 }; return std::string( s, sizeof...( Cs ) ); } }; diff --git a/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp b/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp new file mode 100644 index 0000000000000000000000000000000000000000..798c951e6ab9cb518ab10622b2c4482ca326e537 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp @@ -0,0 +1,154 @@ +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_TRACE_HPP +#define TAO_PEGTL_CONTRIB_TRACE_HPP + +#include <cassert> +#include <iomanip> +#include <iostream> +#include <utility> +#include <vector> + +#include "../config.hpp" +#include "../normal.hpp" + +#include "../internal/demangle.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + template< typename ParseInput > + void print_current( const ParseInput& in ) + { + if( in.empty() ) { + std::cerr << "<eof>"; + } + else { + const auto c = in.peek_uint8(); + switch( c ) { + case 0: + std::cerr << "<nul> = "; + break; + case 9: + std::cerr << "<ht> = "; + break; + case 10: + std::cerr << "<lf> = "; + break; + case 13: + std::cerr << "<cr> = "; + break; + default: + if( isprint( c ) ) { + std::cerr << '\'' << c << "' = "; + } + } + std::cerr << "(char)" << unsigned( c ); + } + } + + } // namespace internal + + struct trace_state + { + unsigned rule = 0; + unsigned line = 0; + std::vector< unsigned > stack; + }; + + template< typename Rule, template< typename... > class Control > + struct basic_trace_control + : Control< Rule > + { + template< typename ParseInput, typename... States > + static void start( const ParseInput& in, States&&... st ) + { + std::cerr << in.position() << " start " << internal::demangle< Rule >() << "; current "; + print_current( in ); + std::cerr << std::endl; + Control< Rule >::start( in, st... ); + } + + template< typename ParseInput, typename... States > + static void start( const ParseInput& in, trace_state& ts, States&&... st ) + { + std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ++ts.rule << " "; + start( in, st... ); + ts.stack.push_back( ts.rule ); + } + + template< typename ParseInput, typename... States > + static void success( const ParseInput& in, States&&... st ) + { + std::cerr << in.position() << " success " << internal::demangle< Rule >() << "; next "; + print_current( in ); + std::cerr << std::endl; + Control< Rule >::success( in, st... ); + } + + template< typename ParseInput, typename... States > + static void success( const ParseInput& in, trace_state& ts, States&&... st ) + { + assert( !ts.stack.empty() ); + std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " "; + success( in, st... ); + ts.stack.pop_back(); + } + + template< typename ParseInput, typename... States > + static void failure( const ParseInput& in, States&&... st ) + { + std::cerr << in.position() << " failure " << internal::demangle< Rule >() << std::endl; + Control< Rule >::failure( in, st... ); + } + + template< typename ParseInput, typename... States > + static void failure( const ParseInput& in, trace_state& ts, States&&... st ) + { + assert( !ts.stack.empty() ); + std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " "; + failure( in, st... ); + ts.stack.pop_back(); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States > + static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) + -> decltype( Control< Rule >::template apply< Action >( begin, in, st... ) ) + { + std::cerr << in.position() << " apply " << internal::demangle< Rule >() << std::endl; + return Control< Rule >::template apply< Action >( begin, in, st... ); + } + + template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States > + static auto apply( const Iterator& begin, const ParseInput& in, trace_state& ts, States&&... st ) + -> decltype( apply< Action >( begin, in, st... ) ) + { + std::cerr << std::setw( 6 ) << ++ts.line << " "; + return apply< Action >( begin, in, st... ); + } + + template< template< typename... > class Action, typename ParseInput, typename... States > + static auto apply0( const ParseInput& in, States&&... st ) + -> decltype( Control< Rule >::template apply0< Action >( in, st... ) ) + { + std::cerr << in.position() << " apply0 " << internal::demangle< Rule >() << std::endl; + return Control< Rule >::template apply0< Action >( in, st... ); + } + + template< template< typename... > class Action, typename ParseInput, typename... States > + static auto apply0( const ParseInput& in, trace_state& ts, States&&... st ) + -> decltype( apply0< Action >( in, st... ) ) + { + std::cerr << std::setw( 6 ) << ++ts.line << " "; + return apply0< Action >( in, st... ); + } + }; + + template< typename Rule > + using trace_control = basic_trace_control< Rule, normal >; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/contrib/tracer.hpp b/packages/PEGTL/include/tao/pegtl/contrib/tracer.hpp deleted file mode 100644 index 3075b7467e9dff07f653a9e06318c66346e798db..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/contrib/tracer.hpp +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_CONTRIB_TRACER_HPP -#define TAO_PEGTL_CONTRIB_TRACER_HPP - -#include <cassert> -#include <iomanip> -#include <iostream> -#include <utility> -#include <vector> - -#include "../config.hpp" -#include "../normal.hpp" - -#include "../internal/demangle.hpp" - -namespace TAO_PEGTL_NAMESPACE -{ - namespace internal - { - template< typename Input > - void print_current( const Input& in ) - { - if( in.empty() ) { - std::cerr << "<eof>"; - } - else { - const auto c = in.peek_uint8(); - switch( c ) { - case 0: - std::cerr << "<nul> = "; - break; - case 9: - std::cerr << "<ht> = "; - break; - case 10: - std::cerr << "<lf> = "; - break; - case 13: - std::cerr << "<cr> = "; - break; - default: - if( isprint( c ) ) { - std::cerr << '\'' << c << "' = "; - } - } - std::cerr << "(char)" << unsigned( c ); - } - } - - } // namespace internal - - struct trace_state - { - unsigned rule = 0; - unsigned line = 0; - std::vector< unsigned > stack; - }; - - template< template< typename... > class Base > - struct trace - { - template< typename Rule > - struct control - : Base< Rule > - { - template< typename Input, typename... States > - static void start( const Input& in, States&&... st ) - { - std::cerr << in.position() << " start " << internal::demangle< Rule >() << "; current "; - print_current( in ); - std::cerr << std::endl; - Base< Rule >::start( in, st... ); - } - - template< typename Input, typename... States > - static void start( const Input& in, trace_state& ts, States&&... st ) - { - std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ++ts.rule << " "; - start( in, st... ); - ts.stack.push_back( ts.rule ); - } - - template< typename Input, typename... States > - static void success( const Input& in, States&&... st ) - { - std::cerr << in.position() << " success " << internal::demangle< Rule >() << "; next "; - print_current( in ); - std::cerr << std::endl; - Base< Rule >::success( in, st... ); - } - - template< typename Input, typename... States > - static void success( const Input& in, trace_state& ts, States&&... st ) - { - assert( !ts.stack.empty() ); - std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " "; - success( in, st... ); - ts.stack.pop_back(); - } - - template< typename Input, typename... States > - static void failure( const Input& in, States&&... st ) - { - std::cerr << in.position() << " failure " << internal::demangle< Rule >() << std::endl; - Base< Rule >::failure( in, st... ); - } - - template< typename Input, typename... States > - static void failure( const Input& in, trace_state& ts, States&&... st ) - { - assert( !ts.stack.empty() ); - std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " "; - failure( in, st... ); - ts.stack.pop_back(); - } - - template< template< typename... > class Action, typename Iterator, typename Input, typename... States > - static auto apply( const Iterator& begin, const Input& in, States&&... st ) - -> decltype( Base< Rule >::template apply< Action >( begin, in, st... ) ) - { - std::cerr << in.position() << " apply " << internal::demangle< Rule >() << std::endl; - return Base< Rule >::template apply< Action >( begin, in, st... ); - } - - template< template< typename... > class Action, typename Iterator, typename Input, typename... States > - static auto apply( const Iterator& begin, const Input& in, trace_state& ts, States&&... st ) - -> decltype( apply< Action >( begin, in, st... ) ) - { - std::cerr << std::setw( 6 ) << ++ts.line << " "; - return apply< Action >( begin, in, st... ); - } - - template< template< typename... > class Action, typename Input, typename... States > - static auto apply0( const Input& in, States&&... st ) - -> decltype( Base< Rule >::template apply0< Action >( in, st... ) ) - { - std::cerr << in.position() << " apply0 " << internal::demangle< Rule >() << std::endl; - return Base< Rule >::template apply0< Action >( in, st... ); - } - - template< template< typename... > class Action, typename Input, typename... States > - static auto apply0( const Input& in, trace_state& ts, States&&... st ) - -> decltype( apply0< Action >( in, st... ) ) - { - std::cerr << std::setw( 6 ) << ++ts.line << " "; - return apply0< Action >( in, st... ); - } - }; - }; - - template< typename Rule > - using tracer = trace< normal >::control< Rule >; - -} // namespace TAO_PEGTL_NAMESPACE - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/uint16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint16.hpp similarity index 95% rename from packages/PEGTL/include/tao/pegtl/uint16.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/uint16.hpp index 80be64908e0dd671c55d97d3de6dc7d8f3718851..54fe468fb71a75b1f60df1795ed03347aa33c5e4 100644 --- a/packages/PEGTL/include/tao/pegtl/uint16.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/uint16.hpp @@ -1,15 +1,15 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_UINT16_HPP -#define TAO_PEGTL_UINT16_HPP +#ifndef TAO_PEGTL_CONTRIB_UINT16_HPP +#define TAO_PEGTL_CONTRIB_UINT16_HPP -#include "config.hpp" +#include "../config.hpp" +#include "../internal/result_on_found.hpp" +#include "../internal/rules.hpp" #include "internal/peek_mask_uint.hpp" #include "internal/peek_uint.hpp" -#include "internal/result_on_found.hpp" -#include "internal/rules.hpp" namespace TAO_PEGTL_NAMESPACE { diff --git a/packages/PEGTL/include/tao/pegtl/uint32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint32.hpp similarity index 95% rename from packages/PEGTL/include/tao/pegtl/uint32.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/uint32.hpp index 60d85cf9d0983e647d257292e110c073eadeff00..31bc321c5b6b639696fee50cce07dba455c7f7f7 100644 --- a/packages/PEGTL/include/tao/pegtl/uint32.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/uint32.hpp @@ -1,15 +1,15 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_UINT32_HPP -#define TAO_PEGTL_UINT32_HPP +#ifndef TAO_PEGTL_CONTRIB_UINT32_HPP +#define TAO_PEGTL_CONTRIB_UINT32_HPP -#include "config.hpp" +#include "../config.hpp" +#include "../internal/result_on_found.hpp" +#include "../internal/rules.hpp" #include "internal/peek_mask_uint.hpp" #include "internal/peek_uint.hpp" -#include "internal/result_on_found.hpp" -#include "internal/rules.hpp" namespace TAO_PEGTL_NAMESPACE { diff --git a/packages/PEGTL/include/tao/pegtl/uint64.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint64.hpp similarity index 95% rename from packages/PEGTL/include/tao/pegtl/uint64.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/uint64.hpp index 5507c5be7ed2af3a950016ac37e6a56b482f267b..027a3968c7fbe697c627371b84f0f417388f046b 100644 --- a/packages/PEGTL/include/tao/pegtl/uint64.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/uint64.hpp @@ -1,15 +1,15 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_UINT64_HPP -#define TAO_PEGTL_UINT64_HPP +#ifndef TAO_PEGTL_CONTRIB_UINT64_HPP +#define TAO_PEGTL_CONTRIB_UINT64_HPP -#include "config.hpp" +#include "../config.hpp" +#include "../internal/result_on_found.hpp" +#include "../internal/rules.hpp" #include "internal/peek_mask_uint.hpp" #include "internal/peek_uint.hpp" -#include "internal/result_on_found.hpp" -#include "internal/rules.hpp" namespace TAO_PEGTL_NAMESPACE { diff --git a/packages/PEGTL/include/tao/pegtl/uint8.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint8.hpp similarity index 90% rename from packages/PEGTL/include/tao/pegtl/uint8.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/uint8.hpp index 1225026568b539dae47cafde4187c6ae7164c8ab..fb094bec80b47d1ff5a12e4c8312e793320fe785 100644 --- a/packages/PEGTL/include/tao/pegtl/uint8.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/uint8.hpp @@ -1,15 +1,15 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_UINT8_HPP -#define TAO_PEGTL_UINT8_HPP +#ifndef TAO_PEGTL_CONTRIB_UINT8_HPP +#define TAO_PEGTL_CONTRIB_UINT8_HPP -#include "config.hpp" +#include "../config.hpp" +#include "../internal/result_on_found.hpp" +#include "../internal/rules.hpp" #include "internal/peek_mask_uint8.hpp" #include "internal/peek_uint8.hpp" -#include "internal/result_on_found.hpp" -#include "internal/rules.hpp" namespace TAO_PEGTL_NAMESPACE::uint8 { diff --git a/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp b/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp index ca3b57bcfbaf5c9b2c5949ca54fb1121e8a0b964..9aca033e8989c92d6b5f910af0cb04e902c14a6c 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_UNESCAPE_HPP @@ -22,7 +22,7 @@ namespace TAO_PEGTL_NAMESPACE::unescape return true; } if( utf32 <= 0x7ff ) { - char tmp[] = { char( ( ( utf32 & 0x7c0 ) >> 6 ) | 0xc0 ), // NOLINT + char tmp[] = { char( ( ( utf32 & 0x7c0 ) >> 6 ) | 0xc0 ), char( ( ( utf32 & 0x03f ) ) | 0x80 ) }; string.append( tmp, sizeof( tmp ) ); return true; @@ -32,14 +32,14 @@ namespace TAO_PEGTL_NAMESPACE::unescape // nope, this is a UTF-16 surrogate return false; } - char tmp[] = { char( ( ( utf32 & 0xf000 ) >> 12 ) | 0xe0 ), // NOLINT + char tmp[] = { char( ( ( utf32 & 0xf000 ) >> 12 ) | 0xe0 ), char( ( ( utf32 & 0x0fc0 ) >> 6 ) | 0x80 ), char( ( ( utf32 & 0x003f ) ) | 0x80 ) }; string.append( tmp, sizeof( tmp ) ); return true; } if( utf32 <= 0x10ffff ) { - char tmp[] = { char( ( ( utf32 & 0x1c0000 ) >> 18 ) | 0xf0 ), // NOLINT + char tmp[] = { char( ( ( utf32 & 0x1c0000 ) >> 18 ) | 0xf0 ), char( ( ( utf32 & 0x03f000 ) >> 12 ) | 0x80 ), char( ( ( utf32 & 0x000fc0 ) >> 6 ) | 0x80 ), char( ( ( utf32 & 0x00003f ) ) | 0x80 ) }; @@ -80,7 +80,7 @@ namespace TAO_PEGTL_NAMESPACE::unescape case 'F': return I( c - 'A' + 10 ); default: // LCOV_EXCL_LINE - throw std::runtime_error( "invalid character in unhex" ); // NOLINT, LCOV_EXCL_LINE + throw std::runtime_error( "invalid character in unhex" ); // LCOV_EXCL_LINE } } @@ -99,8 +99,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape struct append_all { - template< typename Input > - static void apply( const Input& in, std::string& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& s ) { s.append( in.begin(), in.size() ); } @@ -110,22 +110,22 @@ namespace TAO_PEGTL_NAMESPACE::unescape template< typename T, char... Rs > struct unescape_c { - template< typename Input > - static void apply( const Input& in, std::string& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& s ) { assert( in.size() == 1 ); s += apply_one( in, static_cast< const T* >( nullptr ) ); } - template< typename Input, char... Qs > - [[nodiscard]] static char apply_one( const Input& in, const one< Qs... >* /*unused*/ ) + template< typename ActionInput, char... Qs > + [[nodiscard]] static char apply_one( const ActionInput& in, const one< Qs... >* /*unused*/ ) { static_assert( sizeof...( Qs ) == sizeof...( Rs ), "size mismatch between escaped characters and their mappings" ); return apply_two( in, { Qs... }, { Rs... } ); } - template< typename Input > - [[nodiscard]] static char apply_two( const Input& in, const std::initializer_list< char >& q, const std::initializer_list< char >& r ) + template< typename ActionInput > + [[nodiscard]] static char apply_two( const ActionInput& in, const std::initializer_list< char >& q, const std::initializer_list< char >& r ) { const char c = *in.begin(); for( std::size_t i = 0; i < q.size(); ++i ) { @@ -133,7 +133,7 @@ namespace TAO_PEGTL_NAMESPACE::unescape return *( r.begin() + i ); } } - throw parse_error( "invalid character in unescape", in ); // NOLINT, LCOV_EXCL_LINE + throw parse_error( "invalid character in unescape", in ); // LCOV_EXCL_LINE } }; @@ -143,8 +143,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape struct unescape_u { - template< typename Input > - static void apply( const Input& in, std::string& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& s ) { assert( !in.empty() ); // First character MUST be present, usually 'u' or 'U'. if( !utf8_append_utf32( s, unhex_string< unsigned >( in.begin() + 1, in.end() ) ) ) { @@ -155,8 +155,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape struct unescape_x { - template< typename Input > - static void apply( const Input& in, std::string& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& s ) { assert( !in.empty() ); // First character MUST be present, usually 'x'. s += unhex_string< char >( in.begin() + 1, in.end() ); @@ -173,8 +173,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape struct unescape_j { - template< typename Input > - static void apply( const Input& in, std::string& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& s ) { assert( ( ( in.size() + 1 ) % 6 ) == 0 ); // Expects multiple "\\u1234", starting with the first "u". for( const char* b = in.begin() + 1; b < in.end(); b += 6 ) { diff --git a/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp index 06f5e7cf86e1a36014de94a0549ea0cfa15e72cf..90e0a6d911d56af12dd61ead62d731849d3b090b 100644 --- a/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp @@ -1,15 +1,18 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CONTRIB_URI_HPP #define TAO_PEGTL_CONTRIB_URI_HPP +#include <cstdint> + #include "../ascii.hpp" #include "../config.hpp" #include "../rules.hpp" #include "../utf8.hpp" #include "abnf.hpp" +#include "integer.hpp" namespace TAO_PEGTL_NAMESPACE::uri { @@ -25,11 +28,7 @@ namespace TAO_PEGTL_NAMESPACE::uri using colon = one< ':' >; // clang-format off - struct dec_octet : sor< one< '0' >, - rep_min_max< 1, 2, abnf::DIGIT >, - seq< one< '1' >, abnf::DIGIT, abnf::DIGIT >, - seq< one< '2' >, range< '0', '4' >, abnf::DIGIT >, - seq< string< '2', '5' >, range< '0', '5' > > > {}; + struct dec_octet : maximum_rule< std::uint8_t > {}; struct IPv4address : seq< dec_octet, dot, dec_octet, dot, dec_octet, dot, dec_octet > {}; diff --git a/packages/PEGTL/include/tao/pegtl/utf16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/utf16.hpp similarity index 89% rename from packages/PEGTL/include/tao/pegtl/utf16.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/utf16.hpp index 186d1e8e7c36a6259bc28a7d07d5c9265cbed90b..499041408e5f3c501c798ac9afd7bfb7da728e51 100644 --- a/packages/PEGTL/include/tao/pegtl/utf16.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/utf16.hpp @@ -1,14 +1,14 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_UTF16_HPP -#define TAO_PEGTL_UTF16_HPP +#ifndef TAO_PEGTL_CONTRIB_UTF16_HPP +#define TAO_PEGTL_CONTRIB_UTF16_HPP -#include "config.hpp" +#include "../config.hpp" +#include "../internal/result_on_found.hpp" +#include "../internal/rules.hpp" #include "internal/peek_utf16.hpp" -#include "internal/result_on_found.hpp" -#include "internal/rules.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -42,7 +42,7 @@ namespace TAO_PEGTL_NAMESPACE } // namespace utf16_le - namespace utf16 = TAO_PEGTL_NATIVE_UTF16; // NOLINT(misc-unused-alias-decls) + namespace utf16 = TAO_PEGTL_NATIVE_UTF16; } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/include/tao/pegtl/utf32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/utf32.hpp similarity index 89% rename from packages/PEGTL/include/tao/pegtl/utf32.hpp rename to packages/PEGTL/include/tao/pegtl/contrib/utf32.hpp index 591a4cd20e4d8886259a61ca43027372613c591e..ce820fe2080169f4351bacf0c799cf47040d33f8 100644 --- a/packages/PEGTL/include/tao/pegtl/utf32.hpp +++ b/packages/PEGTL/include/tao/pegtl/contrib/utf32.hpp @@ -1,14 +1,14 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_UTF32_HPP -#define TAO_PEGTL_UTF32_HPP +#ifndef TAO_PEGTL_CONTRIB_UTF32_HPP +#define TAO_PEGTL_CONTRIB_UTF32_HPP -#include "config.hpp" +#include "../config.hpp" +#include "../internal/result_on_found.hpp" +#include "../internal/rules.hpp" #include "internal/peek_utf32.hpp" -#include "internal/result_on_found.hpp" -#include "internal/rules.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -42,7 +42,7 @@ namespace TAO_PEGTL_NAMESPACE } // namespace utf32_le - namespace utf32 = TAO_PEGTL_NATIVE_UTF32; // NOLINT(misc-unused-alias-decls) + namespace utf32 = TAO_PEGTL_NATIVE_UTF32; } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp b/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b4958e84399f2af15b0da7b940a2472fe52b16e2 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp @@ -0,0 +1,51 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_CONTRIB_VISIT_RT_HPP +#define TAO_PEGTL_CONTRIB_VISIT_RT_HPP + +#include <set> +#include <string_view> + +#include "../config.hpp" +#include "../type_list.hpp" + +#include "../internal/demangle.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + template< template< typename... > class Func, typename... Rules > + struct visitor_rt + { + template< typename... Args > + static void visit( std::set< std::string_view >& done, Args&&... args ) + { + ( visit_rule< Rules >( typename Rules::subs_t(), done, args... ), ... ); + } + + private: + template< typename Rule, typename... Subs, typename... Args > + static void visit_rule( type_list< Subs... > /*unused*/, std::set< std::string_view >& done, Args&&... args ) + { + if( done.emplace( demangle< Rule >() ).second ) { + Func< Rule >::visit( args... ); + visitor_rt< Func, Subs... >::visit( done, args... ); + } + } + }; + + } // namespace internal + + template< typename Rule, template< typename... > class Func, typename... Args > + std::size_t visit_rt( Args&&... args ) + { + std::set< std::string_view > done; + internal::visitor_rt< Func, Rule >::visit( done, args... ); + return done.size(); + } + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/cstream_input.hpp b/packages/PEGTL/include/tao/pegtl/cstream_input.hpp index 5a5aee72b7b5f2f235d9690cf3851333b1593136..cebc6f7aa6201b877991cd73bb0b5804092848b8 100644 --- a/packages/PEGTL/include/tao/pegtl/cstream_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/cstream_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_CSTREAM_INPUT_HPP @@ -19,10 +19,9 @@ namespace TAO_PEGTL_NAMESPACE : buffer_input< internal::cstream_reader, Eol, std::string, Chunk > { template< typename T > - cstream_input( std::FILE* in_stream, const std::size_t in_maximum, T&& in_source ) // NOLINT + cstream_input( std::FILE* in_stream, const std::size_t in_maximum, T&& in_source ) : buffer_input< internal::cstream_reader, Eol, std::string, Chunk >( std::forward< T >( in_source ), in_maximum, in_stream ) - { - } + {} }; template< typename... Ts > diff --git a/packages/PEGTL/include/tao/pegtl/disable_action.hpp b/packages/PEGTL/include/tao/pegtl/disable_action.hpp index 1832625edb80eb47e0f2ffce6a4e8648032b6085..55872ff8b84902b4e75ea1927b821dedcaae232f 100644 --- a/packages/PEGTL/include/tao/pegtl/disable_action.hpp +++ b/packages/PEGTL/include/tao/pegtl/disable_action.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_DISABLE_ACTION_HPP @@ -22,9 +22,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { return TAO_PEGTL_NAMESPACE::match< Rule, apply_mode::nothing, M, Action, Control >( in, st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/discard_input.hpp b/packages/PEGTL/include/tao/pegtl/discard_input.hpp index 18d3c996a43fded8677bccd120e7834b499e1db4..abf65fee56abe269d691123cc1bd3815dd05f83c 100644 --- a/packages/PEGTL/include/tao/pegtl/discard_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/discard_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_DISCARD_INPUT_HPP @@ -22,11 +22,11 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - const bool result = TAO_PEGTL_NAMESPACE::match< Rule, apply_mode::nothing, M, Action, Control >( in, st... ); + const bool result = TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... ); in.discard(); return result; } diff --git a/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp b/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp index 4f9c99b5e27bdeb4b6bff7b1c1fb5bc1c5d25b27..d3596095e606c3ab0732d5642591cf62d668b204 100644 --- a/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp +++ b/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_DISCARD_INPUT_ON_FAILURE_HPP @@ -22,11 +22,11 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - const bool result = TAO_PEGTL_NAMESPACE::match< Rule, apply_mode::nothing, M, Action, Control >( in, st... ); + const bool result = TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... ); if( !result ) { in.discard(); } diff --git a/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp b/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp index b373d686033486eef0b39d566c35e1bc0716f0bd..5c1ee85a3a5a1d7f6b577a8ee888ee43ef8ee85e 100644 --- a/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp +++ b/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_DISCARD_INPUT_ON_SUCCESS_HPP @@ -22,11 +22,11 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - const bool result = TAO_PEGTL_NAMESPACE::match< Rule, apply_mode::nothing, M, Action, Control >( in, st... ); + const bool result = TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... ); if( result ) { in.discard(); } diff --git a/packages/PEGTL/include/tao/pegtl/enable_action.hpp b/packages/PEGTL/include/tao/pegtl/enable_action.hpp index f0a52e6bfef77b6b082d064d1f85bbb62d85808e..8492df7a46da0e4c802cdc64e4f05c972fb22035 100644 --- a/packages/PEGTL/include/tao/pegtl/enable_action.hpp +++ b/packages/PEGTL/include/tao/pegtl/enable_action.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_ENABLE_ACTION_HPP @@ -22,9 +22,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { return TAO_PEGTL_NAMESPACE::match< Rule, apply_mode::action, M, Action, Control >( in, st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/eol.hpp b/packages/PEGTL/include/tao/pegtl/eol.hpp index 927cd3e5397ba91e2b3531fd7df5248b224d010f..4eeaeba1b985ef3992888e8e3deb9a8c30ca65f3 100644 --- a/packages/PEGTL/include/tao/pegtl/eol.hpp +++ b/packages/PEGTL/include/tao/pegtl/eol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_EOL_HPP diff --git a/packages/PEGTL/include/tao/pegtl/eol_pair.hpp b/packages/PEGTL/include/tao/pegtl/eol_pair.hpp index 4c7f76c12120b4eae571ddda17ae9d28f1c2e08d..f52198b521fb829d7929fa02ce8cbbce6d871e50 100644 --- a/packages/PEGTL/include/tao/pegtl/eol_pair.hpp +++ b/packages/PEGTL/include/tao/pegtl/eol_pair.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_EOL_PAIR_HPP diff --git a/packages/PEGTL/include/tao/pegtl/file_input.hpp b/packages/PEGTL/include/tao/pegtl/file_input.hpp index 3c04e9aca2c1b3d22fac8e1099872f4561a13e38..d54db990fb4bbba59e483a5e5831ff09f9289881 100644 --- a/packages/PEGTL/include/tao/pegtl/file_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/file_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_FILE_INPUT_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/action.hpp b/packages/PEGTL/include/tao/pegtl/internal/action.hpp index c6cd4d1d302130201ccdae93c58a11b8d696b2a1..74e2f418b4efc4927a254b140c5f35819d8ddfeb 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/action.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/action.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ACTION_HPP @@ -6,21 +6,31 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< template< typename... > class Action, typename... Rules > struct action + : action< Action, seq< Rules... > > + {}; + + template< template< typename... > class Action > + struct action< Action > + : success + {}; + + template< template< typename... > class Action, typename Rule > + struct action< Action, Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + using rule_t = action; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode M, @@ -28,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal class, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - return duseltronik< seq< Rules... >, A, M, Action, Control >::match( in, st... ); + return Control< Rule >::template match< A, M, Action, Control >( in, st... ); } }; template< template< typename... > class Action, typename... Rules > - inline constexpr bool skip_control< action< Action, Rules... > > = true; + inline constexpr bool enable_control< action< Action, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp b/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp index 84a97a3f62031e11c0da6378a3f795c83cde13fc..3fff69687738b60a96f4b607a77d0a686929673b 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ACTION_INPUT_HPP @@ -16,18 +16,17 @@ namespace TAO_PEGTL_NAMESPACE::internal { - template< typename Input > + template< typename ParseInput > class action_input { public: - using input_t = Input; - using iterator_t = typename Input::iterator_t; + using input_t = ParseInput; + using iterator_t = typename ParseInput::iterator_t; - action_input( const iterator_t& in_begin, const Input& in_input ) noexcept + action_input( const iterator_t& in_begin, const ParseInput& in_input ) noexcept : m_begin( in_begin ), m_input( in_input ) - { - } + {} action_input( const action_input& ) = delete; action_input( action_input&& ) = delete; @@ -42,7 +41,7 @@ namespace TAO_PEGTL_NAMESPACE::internal return m_begin; } - [[nodiscard]] const Input& input() const noexcept + [[nodiscard]] const ParseInput& input() const noexcept { return m_input; } @@ -52,7 +51,7 @@ namespace TAO_PEGTL_NAMESPACE::internal if constexpr( std::is_same_v< iterator_t, const char* > ) { return iterator(); } - else { // NOLINT + else { return iterator().data; } } @@ -74,7 +73,7 @@ namespace TAO_PEGTL_NAMESPACE::internal [[nodiscard]] std::string string() const { - return std::string( begin(), end() ); + return std::string( begin(), size() ); } [[nodiscard]] std::string_view string_view() const noexcept @@ -99,7 +98,7 @@ namespace TAO_PEGTL_NAMESPACE::internal protected: const iterator_t m_begin; - const Input& m_input; + const ParseInput& m_input; }; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/alnum.hpp b/packages/PEGTL/include/tao/pegtl/internal/alnum.hpp index 459fd3aab91b3a62bf6a3c8f4be653f10d45fdfa..45704b90475acfcc19196b1452416d5d843f2a2f 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/alnum.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/alnum.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ALNUM_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/alpha.hpp b/packages/PEGTL/include/tao/pegtl/internal/alpha.hpp index ddc7cf5fb210389bead2cbb036228515a7e7d5aa..b1591d92b58c847655ee292149b47e135dd54fb4 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/alpha.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/alpha.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ALPHA_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/always_false.hpp b/packages/PEGTL/include/tao/pegtl/internal/always_false.hpp deleted file mode 100644 index 339ab498bf0d39437b05c40bbbed89f493418dcf..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/internal/always_false.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_INTERNAL_ALWAYS_FALSE_HPP -#define TAO_PEGTL_INTERNAL_ALWAYS_FALSE_HPP - -#include "../config.hpp" - -#include <type_traits> - -namespace TAO_PEGTL_NAMESPACE::internal -{ - template< typename... > - struct always_false - : std::false_type - { - }; - -} // namespace TAO_PEGTL_NAMESPACE::internal - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/any.hpp b/packages/PEGTL/include/tao/pegtl/internal/any.hpp index e20c55bc5d7cd77b545fca4f34bf8586734c2a1b..927f257ca931cdf411f04e0328fc3ec051df3aa1 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/any.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/any.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ANY_HPP @@ -6,10 +6,10 @@ #include "../config.hpp" +#include "enable_control.hpp" #include "peek_char.hpp" -#include "skip_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -19,10 +19,11 @@ namespace TAO_PEGTL_NAMESPACE::internal template<> struct any< peek_char > { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = any; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.empty() ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) ) { if( !in.empty() ) { in.bump(); @@ -35,23 +36,22 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Peek > struct any { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = any; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) ) { - if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) { - if( const auto t = Peek::peek( in, s ) ) { - in.bump( t.size ); - return true; - } + if( const auto t = Peek::peek( in ) ) { + in.bump( t.size ); + return true; } return false; } }; template< typename Peek > - inline constexpr bool skip_control< any< Peek > > = true; + inline constexpr bool enable_control< any< Peek > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply.hpp index 11616fcad9303b497aa5444ca5908f746dc83bea..92e24ef26b528eb3a8370ff88ff577b45529e461 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/apply.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/apply.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_APPLY_HPP @@ -7,18 +7,19 @@ #include "../config.hpp" #include "apply_single.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/counted.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename... Actions > struct apply { - using analyze_t = analysis::counted< analysis::rule_type::any, 0 >; + using rule_t = apply; + using subs_t = empty_list; template< apply_mode A, rewind_mode M, @@ -26,16 +27,16 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { if constexpr( ( A == apply_mode::action ) && ( sizeof...( Actions ) > 0 ) ) { - using action_t = typename Input::action_t; + using action_t = typename ParseInput::action_t; const action_t i2( in.iterator(), in ); // No data -- range is from begin to begin. return ( apply_single< Actions >::match( i2, st... ) && ... ); } - else { // NOLINT + else { #if defined( _MSC_VER ) (void)in; (void)( (void)st, ... ); @@ -46,7 +47,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< typename... Actions > - inline constexpr bool skip_control< apply< Actions... > > = true; + inline constexpr bool enable_control< apply< Actions... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp index 417ed7a61197440f6e7a2b169e1406ca2c0eeea0..3ad4b3c2a2800ca4d5e5cc047dc7fcfb469ae417 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_APPLY0_HPP @@ -7,18 +7,19 @@ #include "../config.hpp" #include "apply0_single.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/counted.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename... Actions > struct apply0 { - using analyze_t = analysis::counted< analysis::rule_type::any, 0 >; + using rule_t = apply0; + using subs_t = empty_list; template< apply_mode A, rewind_mode M, @@ -26,14 +27,14 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& /*unused*/, States&&... st ) + [[nodiscard]] static bool match( ParseInput& /*unused*/, States&&... st ) { if constexpr( A == apply_mode::action ) { return ( apply0_single< Actions >::match( st... ) && ... ); } - else { // NOLINT + else { #if defined( _MSC_VER ) (void)( (void)st, ... ); #endif @@ -43,7 +44,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< typename... Actions > - inline constexpr bool skip_control< apply0< Actions... > > = true; + inline constexpr bool enable_control< apply0< Actions... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply0_single.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply0_single.hpp index 73a6f1ac081b275322765d4fd903e2d3d85ee6f6..0c8da5ddd7780736d36394c1e8de2786994f7473 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/apply0_single.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/apply0_single.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_APPLY0_SINGLE_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp index 85dc0b598fd389d8df1227986e0a10c11c3752c1..7120cd0ac2952271b8f1aace7c22a9cbae01d9b7 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_APPLY_SINGLE_HPP @@ -13,16 +13,16 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Action > struct apply_single { - template< typename Input, typename... States > - [[nodiscard]] static auto match( const Input& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) ) + template< typename ActionInput, typename... States > + [[nodiscard]] static auto match( const ActionInput& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) ) -> std::enable_if_t< std::is_same_v< decltype( Action::apply( in, st... ) ), void >, bool > { Action::apply( in, st... ); return true; } - template< typename Input, typename... States > - [[nodiscard]] static auto match( const Input& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) ) + template< typename ActionInput, typename... States > + [[nodiscard]] static auto match( const ActionInput& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) ) -> std::enable_if_t< std::is_same_v< decltype( Action::apply( in, st... ) ), bool >, bool > { return Action::apply( in, st... ); diff --git a/packages/PEGTL/include/tao/pegtl/internal/at.hpp b/packages/PEGTL/include/tao/pegtl/internal/at.hpp index e46a857502665407bc9acb97da468e58c4c72829..df853f71ef7c070f66ab69ad8d0a3f253e07382e 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/at.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/at.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_AT_HPP @@ -6,29 +6,31 @@ #include "../config.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "enable_control.hpp" +#include "seq.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename... Rules > - struct at; + struct at + : at< seq< Rules... > > + {}; template<> struct at<> - : trivial< true > - { - }; + : success + {}; - template< typename... Rules > - struct at + template< typename Rule > + struct at< Rule > { - using analyze_t = analysis::generic< analysis::rule_type::opt, Rules... >; + using rule_t = at; + using subs_t = type_list< Rule >; template< apply_mode, rewind_mode, @@ -36,17 +38,17 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { const auto m = in.template mark< rewind_mode::required >(); - return ( Control< Rules >::template match< apply_mode::nothing, rewind_mode::active, Action, Control >( in, st... ) && ... ); + return Control< Rule >::template match< apply_mode::nothing, rewind_mode::active, Action, Control >( in, st... ); } }; template< typename... Rules > - inline constexpr bool skip_control< at< Rules... > > = true; + inline constexpr bool enable_control< at< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/bof.hpp b/packages/PEGTL/include/tao/pegtl/internal/bof.hpp index 53b8e59c488d30882419e5f27c9567369daff85a..19367f5091cac287d85fa95c4a138ba0d81784e5 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/bof.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/bof.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_BOF_HPP @@ -6,25 +6,26 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { struct bof { - using analyze_t = analysis::generic< analysis::rule_type::opt >; + using rule_t = bof; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept { return in.byte() == 0; } }; template<> - inline constexpr bool skip_control< bof > = true; + inline constexpr bool enable_control< bof > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/bol.hpp b/packages/PEGTL/include/tao/pegtl/internal/bol.hpp index e58d239f3ce53c50e7430eddf6422c5b594c1208..3304cc5d4ff47005570e420c66ed86cc1bb3ce52 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/bol.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/bol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_BOL_HPP @@ -6,25 +6,26 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { struct bol { - using analyze_t = analysis::generic< analysis::rule_type::opt >; + using rule_t = bol; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept { return in.byte_in_line() == 0; } }; template<> - inline constexpr bool skip_control< bol > = true; + inline constexpr bool enable_control< bol > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/bump.hpp b/packages/PEGTL/include/tao/pegtl/internal/bump.hpp index 293b1bbfd86761c049f93e7367d7e0d6bf12413b..74a1a7d7c749d12c55d570d762d590a5aa8aa554 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/bump.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/bump.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_BUMP_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp b/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp index 37b60cd2f14adfb8325218bd8ef091b4cd366ee4..dc9a1779d8834e5f1117e8c72890bcf5b5fd84a1 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_BUMP_HELP_HPP @@ -13,10 +13,10 @@ namespace TAO_PEGTL_NAMESPACE::internal { - template< result_on_found R, typename Input, typename Char, Char... Cs > - void bump_help( Input& in, const std::size_t count ) noexcept + template< result_on_found R, typename ParseInput, typename Char, Char... Cs > + void bump_help( ParseInput& in, const std::size_t count ) noexcept { - if constexpr( ( ( Cs != Input::eol_t::ch ) && ... ) != bool( R ) ) { + if constexpr( ( ( Cs != ParseInput::eol_t::ch ) && ... ) != bool( R ) ) { in.bump( count ); } else { diff --git a/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp b/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp index 9289d0f42a18f61176cee47ebc64d2719d93961e..7bd29960effd86c508a82d95dea7a1697526a89c 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_BYTES_HPP @@ -6,30 +6,37 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" +#include "success.hpp" -#include "../analysis/counted.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { - template< unsigned Num > + template< unsigned Cnt > struct bytes { - using analyze_t = analysis::counted< analysis::rule_type::any, Num >; + using rule_t = bytes; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) ) { - if( in.size( Num ) >= Num ) { - in.bump( Num ); + if( in.size( Cnt ) >= Cnt ) { + in.bump( Cnt ); return true; } return false; } }; - template< unsigned Num > - inline constexpr bool skip_control< bytes< Num > > = true; + template<> + struct bytes< 0 > + : success + {}; + + template< unsigned Cnt > + inline constexpr bool enable_control< bytes< Cnt > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/control.hpp b/packages/PEGTL/include/tao/pegtl/internal/control.hpp index afc30a675082d2aa95cdfe00454d1bfde9f0aa8d..119c98a99f98fae6383d0a2b5c400de5b75c84b3 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/control.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/control.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_CONTROL_HPP @@ -6,21 +6,31 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< template< typename... > class Control, typename... Rules > struct control + : control< Control, seq< Rules... > > + {}; + + template< template< typename... > class Control > + struct control< Control > + : success + {}; + + template< template< typename... > class Control, typename Rule > + struct control< Control, Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + using rule_t = control; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode M, @@ -28,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - return duseltronik< seq< Rules... >, A, M, Action, Control >::match( in, st... ); + return Control< Rule >::template match< A, M, Action, Control >( in, st... ); } }; template< template< typename... > class Control, typename... Rules > - inline constexpr bool skip_control< control< Control, Rules... > > = true; + inline constexpr bool enable_control< control< Control, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp index ff902142cbc05b0be135b80a9ee6a8b1e4833adc..201842bbd1ec4aa80848b46c2d76b3f72980ff27 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_CR_CRLF_EOL_HPP @@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal { static constexpr int ch = '\r'; - template< typename Input > - [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 2 ) ) ) + template< typename ParseInput > + [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 2 ) ) ) { eol_pair p = { false, in.size( 2 ) }; if( p.second ) { diff --git a/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp index cf7d7e07fb8b7720e2639bab9511b927d9a362eb..859dd7f30ba2d17260aaefcdd601c40af664db06 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_CR_EOL_HPP @@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal { static constexpr int ch = '\r'; - template< typename Input > - [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 1 ) ) ) + template< typename ParseInput > + [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 1 ) ) ) { eol_pair p = { false, in.size( 1 ) }; if( p.second ) { diff --git a/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp index 017076f6ddd2c040fc7d8abe6252a882d20d1f47..7a9ad5aa77d9beb238045c67f0a5e57d4e40436c 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_CRLF_EOL_HPP @@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal { static constexpr int ch = '\n'; - template< typename Input > - [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 2 ) ) ) + template< typename ParseInput > + [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 2 ) ) ) { eol_pair p = { false, in.size( 2 ) }; if( p.second > 1 ) { diff --git a/packages/PEGTL/include/tao/pegtl/internal/cstream_reader.hpp b/packages/PEGTL/include/tao/pegtl/internal/cstream_reader.hpp index 1d436eaf5ceacbd646d5873c1f5b415825f150a3..5d46854c6debb092ed18a039958d9dbc0732d67c 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/cstream_reader.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/cstream_reader.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_CSTREAM_READER_HPP @@ -22,7 +22,7 @@ namespace TAO_PEGTL_NAMESPACE::internal assert( m_cstream != nullptr ); } - [[nodiscard]] std::size_t operator()( char* buffer, const std::size_t length ) + [[nodiscard]] std::size_t operator()( char* buffer, const std::size_t length ) const { if( const auto r = std::fread( buffer, 1, length, m_cstream ) ) { return r; diff --git a/packages/PEGTL/include/tao/pegtl/internal/cstring_reader.hpp b/packages/PEGTL/include/tao/pegtl/internal/cstring_reader.hpp index a1f2db454aeca30ddf8aef34f3d708310443f36d..71947aa720af88779bd7402eb4974ecb41945c3c 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/cstring_reader.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/cstring_reader.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_CSTRING_READER_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/demangle.hpp b/packages/PEGTL/include/tao/pegtl/internal/demangle.hpp index 07e55b837065e3314fbf168805a29eed39d08310..183134309bda8bd43843fb10f3db68880fc5788e 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/demangle.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/demangle.hpp @@ -1,28 +1,140 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_DEMANGLE_HPP #define TAO_PEGTL_INTERNAL_DEMANGLE_HPP -#include <string> -#include <typeinfo> +#include <ciso646> +#include <string_view> #include "../config.hpp" -#if defined( __GLIBCXX__ ) || ( defined( __has_include ) && __has_include( <cxxabi.h> ) ) -#include "demangle_cxxabi.hpp" +namespace TAO_PEGTL_NAMESPACE::internal +{ +#if defined( __clang__ ) + +#if defined( _LIBCPP_VERSION ) + + template< typename T > + [[nodiscard]] constexpr std::string_view demangle() noexcept + { + constexpr std::string_view sv = __PRETTY_FUNCTION__; + constexpr auto begin = sv.find( '=' ); + static_assert( begin != std::string_view::npos ); + return sv.substr( begin + 2, sv.size() - begin - 3 ); + } + #else -#include "demangle_nop.hpp" + + // When using libstdc++ with clang, std::string_view::find is not constexpr :( + template< char C > + constexpr const char* find( const char* p, std::size_t n ) noexcept + { + while( n ) { + if( *p == C ) { + return p; + } + ++p; + --n; + } + return nullptr; + } + + template< typename T > + [[nodiscard]] constexpr std::string_view demangle() noexcept + { + constexpr std::string_view sv = __PRETTY_FUNCTION__; + constexpr auto begin = find< '=' >( sv.data(), sv.size() ); + static_assert( begin != nullptr ); + return { begin + 2, sv.data() + sv.size() - begin - 3 }; + } + #endif -namespace TAO_PEGTL_NAMESPACE::internal -{ +#elif defined( __GNUC__ ) + +#if( __GNUC__ == 7 ) + + // GCC 7 wrongly sometimes disallows __PRETTY_FUNCTION__ in constexpr functions, + // therefore we drop the 'constexpr' and hope for the best. + template< typename T > + [[nodiscard]] std::string_view demangle() noexcept + { + const std::string_view sv = __PRETTY_FUNCTION__; + const auto begin = sv.find( '=' ); + const auto tmp = sv.substr( begin + 2 ); + const auto end = tmp.rfind( ';' ); + return tmp.substr( 0, end ); + } + +#elif( __GNUC__ == 9 ) && ( __GNUC_MINOR__ < 3 ) + + // GCC 9.1 and 9.2 have a bug that leads to truncated __PRETTY_FUNCTION__ names, + // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91155 template< typename T > - [[nodiscard]] std::string demangle() + [[nodiscard]] constexpr std::string_view demangle() noexcept { - return demangle( typeid( T ).name() ); + // fallback: requires RTTI, no demangling + return typeid( T ).name(); } +#else + + template< typename T > + [[nodiscard]] constexpr std::string_view demangle() noexcept + { + constexpr std::string_view sv = __PRETTY_FUNCTION__; + constexpr auto begin = sv.find( '=' ); + static_assert( begin != std::string_view::npos ); + constexpr auto tmp = sv.substr( begin + 2 ); + constexpr auto end = tmp.rfind( ';' ); + static_assert( end != std::string_view::npos ); + return tmp.substr( 0, end ); + } + +#endif + +#elif defined( _MSC_VER ) + +#if( _MSC_VER < 1920 ) + + template< typename T > + [[nodiscard]] constexpr std::string_view demangle() noexcept + { + const std::string_view sv = __FUNCSIG__; + const auto begin = sv.find( "demangle<" ); + const auto tmp = sv.substr( begin + 9 ); + const auto end = tmp.rfind( '>' ); + return tmp.substr( 0, end ); + } + +#else + + template< typename T > + [[nodiscard]] constexpr std::string_view demangle() noexcept + { + constexpr std::string_view sv = __FUNCSIG__; + constexpr auto begin = sv.find( "demangle<" ); + static_assert( begin != std::string_view::npos ); + constexpr auto tmp = sv.substr( begin + 9 ); + constexpr auto end = tmp.rfind( '>' ); + static_assert( end != std::string_view::npos ); + return tmp.substr( 0, end ); + } + +#endif + +#else + + template< typename T > + [[nodiscard]] constexpr std::string_view demangle() noexcept + { + // fallback: requires RTTI, no demangling + return typeid( T ).name(); + } + +#endif + } // namespace TAO_PEGTL_NAMESPACE::internal #endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/demangle_cxxabi.hpp b/packages/PEGTL/include/tao/pegtl/internal/demangle_cxxabi.hpp deleted file mode 100644 index a7e5bc7bb16466c6b3c75bdece882e49a33a2661..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/internal/demangle_cxxabi.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_INTERNAL_DEMANGLE_CXXABI_HPP -#define TAO_PEGTL_INTERNAL_DEMANGLE_CXXABI_HPP - -#include <cstdlib> -#include <cxxabi.h> -#include <memory> -#include <string> - -#include "../config.hpp" - -#include "demangle_sanitise.hpp" - -namespace TAO_PEGTL_NAMESPACE::internal -{ - [[nodiscard]] inline std::string demangle( const char* symbol ) - { - const std::unique_ptr< char, decltype( &std::free ) > demangled( abi::__cxa_demangle( symbol, nullptr, nullptr, nullptr ), &std::free ); - if( !demangled ) { - return symbol; - } - std::string result( demangled.get() ); -#if defined( TAO_PEGTL_PRETTY_DEMANGLE ) - demangle_sanitise_chars( result ); // LCOV_EXCL_LINE -#endif - return result; - } - -} // namespace TAO_PEGTL_NAMESPACE::internal - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/demangle_nop.hpp b/packages/PEGTL/include/tao/pegtl/internal/demangle_nop.hpp deleted file mode 100644 index b178f040cae75662b753751ad95dc6580a82391b..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/internal/demangle_nop.hpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_INTERNAL_DEMANGLE_NOP_HPP -#define TAO_PEGTL_INTERNAL_DEMANGLE_NOP_HPP - -#include <string> - -#include "../config.hpp" - -namespace TAO_PEGTL_NAMESPACE::internal -{ - [[nodiscard]] inline std::string demangle( const char* symbol ) - { - return symbol; - } - -} // namespace TAO_PEGTL_NAMESPACE::internal - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/demangle_sanitise.hpp b/packages/PEGTL/include/tao/pegtl/internal/demangle_sanitise.hpp deleted file mode 100644 index 47f7549c6540e32bbb5ef24f01010315885c37f6..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/internal/demangle_sanitise.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_INTERNAL_DEMANGLE_SANITISE_HPP -#define TAO_PEGTL_INTERNAL_DEMANGLE_SANITISE_HPP - -#include <string> - -#include "../config.hpp" - -namespace TAO_PEGTL_NAMESPACE::internal -{ - inline void demangle_sanitise_chars( std::string& s ) - { - std::string::size_type p; - while( ( p = s.find( "(char)" ) ) != std::string::npos ) { - int c = 0; - std::string::size_type q; - for( q = p + 6; ( q < s.size() ) && ( s[ q ] >= '0' ) && ( s[ q ] <= '9' ); ++q ) { - c *= 10; - c += s[ q ] - '0'; - } - if( c == '\'' ) { - s.replace( p, q - p, "'\\''" ); - } - else if( c == '\\' ) { - s.replace( p, q - p, "'\\\\'" ); - } - else if( ( c < 32 ) || ( c > 126 ) ) { - s.replace( p, 6, std::string() ); - } - else { - s.replace( p, q - p, std::string( 1, '\'' ) + char( c ) + '\'' ); - } - } - } - -} // namespace TAO_PEGTL_NAMESPACE::internal - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/dependent_false.hpp b/packages/PEGTL/include/tao/pegtl/internal/dependent_false.hpp new file mode 100644 index 0000000000000000000000000000000000000000..421dc496c32bfb0feec765db76617f9a38fd0a01 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/internal/dependent_false.hpp @@ -0,0 +1,16 @@ +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_INTERNAL_DEPENDENT_FALSE_HPP +#define TAO_PEGTL_INTERNAL_DEPENDENT_FALSE_HPP + +#include "../config.hpp" + +namespace TAO_PEGTL_NAMESPACE::internal +{ + template< typename... > + inline constexpr bool dependent_false = false; + +} // namespace TAO_PEGTL_NAMESPACE::internal + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/disable.hpp b/packages/PEGTL/include/tao/pegtl/internal/disable.hpp index 10e878d31f0378867c564a789065f41c4eb6a0b3..727f5eafd2b5839909b5c42a930d41e1577a8dab 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/disable.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/disable.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_DISABLE_HPP @@ -6,21 +6,31 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename... Rules > struct disable + : disable< seq< Rules... > > + {}; + + template<> + struct disable<> + : success + {}; + + template< typename Rule > + struct disable< Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + using rule_t = disable; + using subs_t = type_list< Rule >; template< apply_mode, rewind_mode M, @@ -28,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - return duseltronik< seq< Rules... >, apply_mode::nothing, M, Action, Control >::match( in, st... ); + return Control< Rule >::template match< apply_mode::nothing, M, Action, Control >( in, st... ); } }; template< typename... Rules > - inline constexpr bool skip_control< disable< Rules... > > = true; + inline constexpr bool enable_control< disable< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/discard.hpp b/packages/PEGTL/include/tao/pegtl/internal/discard.hpp index ffd5ff431fc9136f67ee056a570798e4ecbdb06b..2b0b55af1ae691acbc0d390e7ff0892d6cd1bbe7 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/discard.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/discard.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_DISCARD_HPP @@ -6,18 +6,19 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { struct discard { - using analyze_t = analysis::generic< analysis::rule_type::opt >; + using rule_t = discard; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept { static_assert( noexcept( in.discard() ) ); in.discard(); @@ -26,7 +27,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template<> - inline constexpr bool skip_control< discard > = true; + inline constexpr bool enable_control< discard > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/dusel_mode.hpp b/packages/PEGTL/include/tao/pegtl/internal/dusel_mode.hpp index 3a40eba3a67545802215919a84642b7143c9a96f..dadba26303728559424379934ab53eef38d4a3c1 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/dusel_mode.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/dusel_mode.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_DUSEL_MODE_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp b/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp index 6f1ca814e076e1d2f5dcf3ecee80622b4ea33059..53555e9faf04b63311c39eb15234fb35a9518db2 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_DUSELTRONIK_HPP @@ -10,6 +10,11 @@ #include "dusel_mode.hpp" +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4702 ) +#endif + namespace TAO_PEGTL_NAMESPACE::internal { template< typename Rule, @@ -31,15 +36,15 @@ namespace TAO_PEGTL_NAMESPACE::internal class Control > struct duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing > { - template< typename Input, typename... States > - [[nodiscard]] static auto match( Input& in, States&&... st ) + template< typename ParseInput, typename... States > + [[nodiscard]] static auto match( ParseInput& in, States&&... st ) -> decltype( Rule::template match< A, M, Action, Control >( in, st... ) ) { return Rule::template match< A, M, Action, Control >( in, st... ); } - template< typename Input, typename... States, int = 1 > - [[nodiscard]] static auto match( Input& in, States&&... /*unused*/ ) + template< typename ParseInput, typename... States, int = 1 > + [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ ) -> decltype( Rule::match( in ) ) { return Rule::match( in ); @@ -55,16 +60,16 @@ namespace TAO_PEGTL_NAMESPACE::internal class Control > struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control > { - template< typename Input, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + template< typename ParseInput, typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - Control< Rule >::start( static_cast< const Input& >( in ), st... ); + Control< Rule >::start( static_cast< const ParseInput& >( in ), st... ); if( duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >::match( in, st... ) ) { - Control< Rule >::success( static_cast< const Input& >( in ), st... ); + Control< Rule >::success( static_cast< const ParseInput& >( in ), st... ); return true; } - Control< Rule >::failure( static_cast< const Input& >( in ), st... ); + Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... ); return false; } }; @@ -78,19 +83,19 @@ namespace TAO_PEGTL_NAMESPACE::internal class Control > struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply_void > { - template< typename Input, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + template< typename ParseInput, typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< rewind_mode::required >(); - Control< Rule >::start( static_cast< const Input& >( in ), st... ); + Control< Rule >::start( static_cast< const ParseInput& >( in ), st... ); if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) { - Control< Rule >::template apply< Action >( m.iterator(), static_cast< const Input& >( in ), st... ); - Control< Rule >::success( static_cast< const Input& >( in ), st... ); + Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... ); + Control< Rule >::success( static_cast< const ParseInput& >( in ), st... ); return m( true ); } - Control< Rule >::failure( static_cast< const Input& >( in ), st... ); + Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... ); return false; } }; @@ -104,20 +109,20 @@ namespace TAO_PEGTL_NAMESPACE::internal class Control > struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply_bool > { - template< typename Input, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + template< typename ParseInput, typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< rewind_mode::required >(); - Control< Rule >::start( static_cast< const Input& >( in ), st... ); + Control< Rule >::start( static_cast< const ParseInput& >( in ), st... ); if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) { - if( Control< Rule >::template apply< Action >( m.iterator(), static_cast< const Input& >( in ), st... ) ) { - Control< Rule >::success( static_cast< const Input& >( in ), st... ); + if( Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... ) ) { + Control< Rule >::success( static_cast< const ParseInput& >( in ), st... ); return m( true ); } } - Control< Rule >::failure( static_cast< const Input& >( in ), st... ); + Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... ); return false; } }; @@ -131,17 +136,17 @@ namespace TAO_PEGTL_NAMESPACE::internal class Control > struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply0_void > { - template< typename Input, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + template< typename ParseInput, typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - Control< Rule >::start( static_cast< const Input& >( in ), st... ); + Control< Rule >::start( static_cast< const ParseInput& >( in ), st... ); if( duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >::match( in, st... ) ) { - Control< Rule >::template apply0< Action >( static_cast< const Input& >( in ), st... ); - Control< Rule >::success( static_cast< const Input& >( in ), st... ); + Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... ); + Control< Rule >::success( static_cast< const ParseInput& >( in ), st... ); return true; } - Control< Rule >::failure( static_cast< const Input& >( in ), st... ); + Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... ); return false; } }; @@ -155,24 +160,28 @@ namespace TAO_PEGTL_NAMESPACE::internal class Control > struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply0_bool > { - template< typename Input, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + template< typename ParseInput, typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< rewind_mode::required >(); - Control< Rule >::start( static_cast< const Input& >( in ), st... ); + Control< Rule >::start( static_cast< const ParseInput& >( in ), st... ); if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) { - if( Control< Rule >::template apply0< Action >( static_cast< const Input& >( in ), st... ) ) { - Control< Rule >::success( static_cast< const Input& >( in ), st... ); + if( Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... ) ) { + Control< Rule >::success( static_cast< const ParseInput& >( in ), st... ); return m( true ); } } - Control< Rule >::failure( static_cast< const Input& >( in ), st... ); + Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... ); return false; } }; } // namespace TAO_PEGTL_NAMESPACE::internal +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + #endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/enable.hpp b/packages/PEGTL/include/tao/pegtl/internal/enable.hpp index 7da5fb80e519867f01fbdc84ec7c5af6c3e45bc7..e30e97b8a3bc92b886870feb23b43725dfb4e4dc 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/enable.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/enable.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ENABLE_HPP @@ -6,21 +6,31 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename... Rules > struct enable + : enable< seq< Rules... > > + {}; + + template<> + struct enable<> + : success + {}; + + template< typename Rule > + struct enable< Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + using rule_t = enable; + using subs_t = type_list< Rule >; template< apply_mode, rewind_mode M, @@ -28,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - return duseltronik< seq< Rules... >, apply_mode::action, M, Action, Control >::match( in, st... ); + return Control< Rule >::template match< apply_mode::action, M, Action, Control >( in, st... ); } }; template< typename... Rules > - inline constexpr bool skip_control< enable< Rules... > > = true; + inline constexpr bool enable_control< enable< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/skip_control.hpp b/packages/PEGTL/include/tao/pegtl/internal/enable_control.hpp similarity index 59% rename from packages/PEGTL/include/tao/pegtl/internal/skip_control.hpp rename to packages/PEGTL/include/tao/pegtl/internal/enable_control.hpp index a3b7704632fe48e4ac6ef5ba4a28cbb69ac31af2..d424b5d79e460a4bdc2f6d3f8a187a8fa6259650 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/skip_control.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/enable_control.hpp @@ -1,8 +1,8 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_INTERNAL_SKIP_CONTROL_HPP -#define TAO_PEGTL_INTERNAL_SKIP_CONTROL_HPP +#ifndef TAO_PEGTL_INTERNAL_ENABLE_CONTROL_HPP +#define TAO_PEGTL_INTERNAL_ENABLE_CONTROL_HPP #include <type_traits> @@ -11,14 +11,14 @@ namespace TAO_PEGTL_NAMESPACE::internal { // This class is a simple tagging mechanism. - // By default, skip_control< Rule > is 'false'. + // By default, enable_control< Rule > is 'true'. // Each internal (!) rule that should be hidden // from the control and action class' callbacks - // simply specializes skip_control<> to return + // simply specializes enable_control<> to return // 'true' for the above expression. template< typename Rule > - inline constexpr bool skip_control = false; + inline constexpr bool enable_control = true; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/eof.hpp b/packages/PEGTL/include/tao/pegtl/internal/eof.hpp index bce5fe267066c5691a3d711e0b855b28e912fa47..7dddc14456129c29a1913029911160aa44e6dd32 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/eof.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/eof.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_EOF_HPP @@ -6,25 +6,26 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { struct eof { - using analyze_t = analysis::generic< analysis::rule_type::opt >; + using rule_t = eof; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.empty() ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) ) { return in.empty(); } }; template<> - inline constexpr bool skip_control< eof > = true; + inline constexpr bool enable_control< eof > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/eol.hpp index d764bccc0238adcbaf703372da1e6d97dee135d0..38f5fb7e5ab9229559b7a36aa1500f6081803125 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/eol.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/eol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_EOL_HPP @@ -6,25 +6,26 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { struct eol { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = eol; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( Input::eol_t::match( in ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( ParseInput::eol_t::match( in ) ) ) { - return Input::eol_t::match( in ).first; + return ParseInput::eol_t::match( in ).first; } }; template<> - inline constexpr bool skip_control< eol > = true; + inline constexpr bool enable_control< eol > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp b/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp index 6e9299686812b07bf87110d06b11aa1078d4830a..eb03141fbd67c5bdd1dc9a87d61ea362f2b492f1 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_EOLF_HPP @@ -6,26 +6,27 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { struct eolf { - using analyze_t = analysis::generic< analysis::rule_type::opt >; + using rule_t = eolf; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( Input::eol_t::match( in ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( ParseInput::eol_t::match( in ) ) ) { - const auto p = Input::eol_t::match( in ); + const auto p = ParseInput::eol_t::match( in ); return p.first || ( !p.second ); } }; template<> - inline constexpr bool skip_control< eolf > = true; + inline constexpr bool enable_control< eolf > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/failure.hpp b/packages/PEGTL/include/tao/pegtl/internal/failure.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e8cfaa4ef8bf4e7d5d662e14d945978eafa1a75d --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/internal/failure.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_INTERNAL_FAILURE_HPP +#define TAO_PEGTL_INTERNAL_FAILURE_HPP + +#include "../config.hpp" + +#include "enable_control.hpp" + +#include "../type_list.hpp" + +namespace TAO_PEGTL_NAMESPACE::internal +{ + struct failure + { + using rule_t = failure; + using subs_t = empty_list; + + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& /*unused*/ ) noexcept + { + return false; + } + }; + + template<> + inline constexpr bool enable_control< failure > = false; + +} // namespace TAO_PEGTL_NAMESPACE::internal + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp index b639f052e214ba942a9dd8a58e91d02dd822a65b..cd4b5663e1c14c479835f1d2f7bfa88d48844bb5 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_FILE_MAPPER_POSIX_HPP @@ -20,8 +20,7 @@ namespace TAO_PEGTL_NAMESPACE::internal public: explicit file_mapper( const char* filename ) : file_mapper( file_opener( filename ) ) - { - } + {} explicit file_mapper( const file_opener& reader ) : m_size( reader.size() ), @@ -39,7 +38,7 @@ namespace TAO_PEGTL_NAMESPACE::internal ~file_mapper() noexcept { // Legacy C interface requires pointer-to-mutable but does not write through the pointer. - ::munmap( const_cast< char* >( m_data ), m_size ); // NOLINT + ::munmap( const_cast< char* >( m_data ), m_size ); } void operator=( const file_mapper& ) = delete; diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp index a705da097e7d887b29f30a298a3147d168d53634..27f9eaf955f141de0c02478d93d02a518af1bade 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_FILE_MAPPER_WIN32_HPP @@ -37,8 +37,7 @@ namespace TAO_PEGTL_NAMESPACE::internal explicit win32_file_opener( const char* filename ) : m_source( filename ), m_handle( open() ) - { - } + {} win32_file_opener( const win32_file_opener& ) = delete; win32_file_opener( win32_file_opener&& ) = delete; @@ -102,14 +101,12 @@ namespace TAO_PEGTL_NAMESPACE::internal { explicit win32_file_mapper( const char* filename ) : win32_file_mapper( win32_file_opener( filename ) ) - { - } + {} explicit win32_file_mapper( const win32_file_opener& reader ) : m_size( reader.size() ), m_handle( open( reader ) ) - { - } + {} win32_file_mapper( const win32_file_mapper& ) = delete; win32_file_mapper( win32_file_mapper&& ) = delete; @@ -153,8 +150,7 @@ namespace TAO_PEGTL_NAMESPACE::internal public: explicit file_mapper( const char* filename ) : file_mapper( win32_file_mapper( filename ) ) - { - } + {} explicit file_mapper( const win32_file_mapper& mapper ) : m_size( mapper.m_size ), diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_opener.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_opener.hpp index 3ab1be783c3920eadd03513a0268ce58703662d4..5f2521b6b1e3eafc4a7b294e8ce65f0dc2426c21 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/file_opener.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/file_opener.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_FILE_OPENER_HPP @@ -21,8 +21,7 @@ namespace TAO_PEGTL_NAMESPACE::internal explicit file_opener( const char* filename ) : m_source( filename ), m_fd( open() ) - { - } + {} file_opener( const file_opener& ) = delete; file_opener( file_opener&& ) = delete; @@ -37,7 +36,7 @@ namespace TAO_PEGTL_NAMESPACE::internal [[nodiscard]] std::size_t size() const { - struct stat st; // NOLINT + struct stat st; errno = 0; if( ::fstat( m_fd, &st ) < 0 ) { const auto ec = errno; @@ -53,7 +52,7 @@ namespace TAO_PEGTL_NAMESPACE::internal [[nodiscard]] int open() const { errno = 0; - const int fd = ::open( m_source, // NOLINT + const int fd = ::open( m_source, O_RDONLY #if defined( O_CLOEXEC ) | O_CLOEXEC diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp index 5b48f4bb08b907f797d821c988538ae6adcbe243..ac098e5921edae0d14f0ed7efe7e298670b95c9a 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_FILE_READER_HPP @@ -21,9 +21,9 @@ namespace TAO_PEGTL_NAMESPACE::internal std::FILE* file; if( ::fopen_s( &file, filename, "rb" ) == 0 ) #elif defined( __MINGW32__ ) - if( auto* file = std::fopen( filename, "rb" ) ) // NOLINT(cppcoreguidelines-owning-memory) + if( auto* file = std::fopen( filename, "rb" ) ) #else - if( auto* file = std::fopen( filename, "rbe" ) ) // NOLINT(cppcoreguidelines-owning-memory) + if( auto* file = std::fopen( filename, "rbe" ) ) #endif { return file; @@ -36,7 +36,7 @@ namespace TAO_PEGTL_NAMESPACE::internal { void operator()( FILE* f ) const noexcept { - std::fclose( f ); // NOLINT(cppcoreguidelines-owning-memory) + std::fclose( f ); } }; @@ -46,14 +46,12 @@ namespace TAO_PEGTL_NAMESPACE::internal explicit file_reader( const char* filename ) : m_source( filename ), m_file( file_open( m_source ) ) - { - } + {} file_reader( FILE* file, const char* filename ) noexcept : m_source( filename ), m_file( file ) - { - } + {} file_reader( const file_reader& ) = delete; file_reader( file_reader&& ) = delete; diff --git a/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp index 2c91aed89df884df58e26578dc63061491bccc84..8c9414aac85760ea1befd6bd810f5726c88a506a 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp @@ -1,24 +1,20 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_HAS_APPLY_HPP #define TAO_PEGTL_INTERNAL_HAS_APPLY_HPP -#include <type_traits> +#include <utility> #include "../config.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename, typename, template< typename... > class, typename... > - struct has_apply - : std::false_type - {}; + inline constexpr bool has_apply = false; template< typename C, template< typename... > class Action, typename... S > - struct has_apply< C, decltype( C::template apply< Action >( std::declval< S >()... ) ), Action, S... > - : std::true_type - {}; + inline constexpr bool has_apply< C, decltype( C::template apply< Action >( std::declval< S >()... ) ), Action, S... > = true; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp index b2319e8cef2e919f217dcdeb9ed8fc819bdb1832..db49981a3b61df20a9c9e13e706e6270e9334b61 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp @@ -1,24 +1,20 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_HAS_APPLY0_HPP #define TAO_PEGTL_INTERNAL_HAS_APPLY0_HPP -#include <type_traits> +#include <utility> #include "../config.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename, typename, template< typename... > class, typename... > - struct has_apply0 - : std::false_type - {}; + inline constexpr bool has_apply0 = false; template< typename C, template< typename... > class Action, typename... S > - struct has_apply0< C, decltype( C::template apply0< Action >( std::declval< S >()... ) ), Action, S... > - : std::true_type - {}; + inline constexpr bool has_apply0< C, decltype( C::template apply0< Action >( std::declval< S >()... ) ), Action, S... > = true; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp b/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp index 08186d622838fb105edb03ec16c77f760df67649..5b2892d959ee8c75167073e23c6a6cde9b5c82f6 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp @@ -1,10 +1,9 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_HAS_MATCH_HPP #define TAO_PEGTL_INTERNAL_HAS_MATCH_HPP -#include <type_traits> #include <utility> #include "../apply_mode.hpp" @@ -21,11 +20,9 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - struct has_match - : std::false_type - {}; + inline constexpr bool has_match = false; template< typename Rule, apply_mode A, @@ -34,22 +31,9 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - struct has_match< decltype( (void)Action< Rule >::template match< Rule, A, M, Action, Control >( std::declval< Input& >(), std::declval< States&& >()... ), void() ), Rule, A, M, Action, Control, Input, States... > - : std::true_type - {}; - - template< typename Rule, - apply_mode A, - rewind_mode M, - template< typename... > - class Action, - template< typename... > - class Control, - typename Input, - typename... States > - inline constexpr bool has_match_v = has_match< void, Rule, A, M, Action, Control, Input, States... >::value; + inline constexpr bool has_match< decltype( (void)Action< Rule >::template match< Rule, A, M, Action, Control >( std::declval< ParseInput& >(), std::declval< States&& >()... ), bool() ), Rule, A, M, Action, Control, ParseInput, States... > = true; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/identifier.hpp b/packages/PEGTL/include/tao/pegtl/internal/identifier.hpp index ce666df2b97a4c85f22ff3ca72bfd6c926af95ed..f75eebd1406c3826734c8747305106134cebbbd0 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/identifier.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/identifier.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_IDENTIFIER_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp index 342d94447f00ff27bb5e31761cf087cadaeefd17..4ccfb9c1ff19645d130f0d63c70349c41e79172d 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_IF_APPLY_HPP @@ -7,18 +7,19 @@ #include "../config.hpp" #include "apply_single.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/counted.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename Rule, typename... Actions > struct if_apply { - using analyze_t = typename Rule::analyze_t; + using rule_t = if_apply; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode M, @@ -26,12 +27,12 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { if constexpr( ( A == apply_mode::action ) && ( sizeof...( Actions ) != 0 ) ) { - using action_t = typename Input::action_t; + using action_t = typename ParseInput::action_t; auto m = in.template mark< rewind_mode::required >(); if( Control< Rule >::template match< apply_mode::action, rewind_mode::active, Action, Control >( in, st... ) ) { const action_t i2( m.iterator(), in ); @@ -39,14 +40,14 @@ namespace TAO_PEGTL_NAMESPACE::internal } return false; } - else { // NOLINT + else { return Control< Rule >::template match< A, M, Action, Control >( in, st... ); } } }; template< typename Rule, typename... Actions > - inline constexpr bool skip_control< if_apply< Rule, Actions... > > = true; + inline constexpr bool enable_control< if_apply< Rule, Actions... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp index 8b4bf328d707f486e789a464b4eea84e402ee568..68689f32338e7b94d8e0c739f021dff31319e914 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_IF_MUST_HPP @@ -6,21 +6,20 @@ #include "../config.hpp" +#include "enable_control.hpp" #include "must.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/counted.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< bool Default, typename Cond, typename... Rules > struct if_must { - using analyze_t = analysis::counted< analysis::rule_type::seq, Default ? 0 : 1, Cond, must< Rules... > >; + using rule_t = if_must; + using subs_t = type_list< Cond, must< Rules... > >; template< apply_mode A, rewind_mode M, @@ -28,12 +27,12 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { if( Control< Cond >::template match< A, M, Action, Control >( in, st... ) ) { - (void)( Control< must< Rules > >::template match< A, M, Action, Control >( in, st... ) && ... ); + (void)Control< must< Rules... > >::template match< A, M, Action, Control >( in, st... ); return true; } return Default; @@ -41,7 +40,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< bool Default, typename Cond, typename... Rules > - inline constexpr bool skip_control< if_must< Default, Cond, Rules... > > = true; + inline constexpr bool enable_control< if_must< Default, Cond, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp index 932ed2ac1172587c688d16ac1df2cb856f83ac71..bad4358d6e5ff19d71b529527c1f7fe0e03f97f4 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_IF_MUST_ELSE_HPP @@ -9,6 +9,8 @@ #include "if_then_else.hpp" #include "must.hpp" +#include "../type_list.hpp" + namespace TAO_PEGTL_NAMESPACE::internal { template< typename Cond, typename Then, typename Else > diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp index 88a8893116af9255e93e0b22beb6e75e92f1bb3d..ea0bf8a31954e8055c72e630d6f3f1231fda8280 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_IF_THEN_ELSE_HPP @@ -6,22 +6,22 @@ #include "../config.hpp" +#include "enable_control.hpp" #include "not_at.hpp" #include "seq.hpp" -#include "skip_control.hpp" #include "sor.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename Cond, typename Then, typename Else > struct if_then_else { - using analyze_t = analysis::generic< analysis::rule_type::sor, seq< Cond, Then >, seq< not_at< Cond >, Else > >; + using rule_t = if_then_else; + using subs_t = type_list< Cond, Then, Else >; template< apply_mode A, rewind_mode M, @@ -29,9 +29,9 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< M >(); using m_t = decltype( m ); @@ -44,7 +44,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< typename Cond, typename Then, typename Else > - inline constexpr bool skip_control< if_then_else< Cond, Then, Else > > = true; + inline constexpr bool enable_control< if_then_else< Cond, Then, Else > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/input_pair.hpp b/packages/PEGTL/include/tao/pegtl/internal/input_pair.hpp index 976e3eb53983297e654adaef3bf193d98123d2f0..78dde050a7063af0cc6f95b3f95c31056d72b2f9 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/input_pair.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/input_pair.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_INPUT_PAIR_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/istream_reader.hpp b/packages/PEGTL/include/tao/pegtl/internal/istream_reader.hpp index b928a48a1758e6db355ba5f772fa21f179b71acf..fa91b960daf466358a3d7a9a061da09cc3bc4ed3 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/istream_reader.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/istream_reader.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ISTREAM_READER_HPP @@ -15,8 +15,7 @@ namespace TAO_PEGTL_NAMESPACE::internal { explicit istream_reader( std::istream& s ) noexcept : m_istream( s ) - { - } + {} [[nodiscard]] std::size_t operator()( char* buffer, const std::size_t length ) { diff --git a/packages/PEGTL/include/tao/pegtl/internal/istring.hpp b/packages/PEGTL/include/tao/pegtl/internal/istring.hpp index 4e9ce895d0dd1e7cde4e131af89a255fd7d9bde0..60e6a2fe2025f50b0086a8110f8e363e3dba84dc 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/istring.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/istring.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ISTRING_HPP @@ -9,11 +9,11 @@ #include "../config.hpp" #include "bump_help.hpp" +#include "enable_control.hpp" #include "result_on_found.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "success.hpp" -#include "../analysis/counted.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -26,7 +26,7 @@ namespace TAO_PEGTL_NAMESPACE::internal if constexpr( is_alpha< C > ) { return ( C | 0x20 ) == ( c | 0x20 ); } - else { // NOLINT + else { return c == C; } } @@ -42,21 +42,21 @@ namespace TAO_PEGTL_NAMESPACE::internal template<> struct istring<> - : trivial< true > - { - }; + : success + {}; template< char... Cs > struct istring { - using analyze_t = analysis::counted< analysis::rule_type::any, sizeof...( Cs ) >; + using rule_t = istring; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) ) { if( in.size( sizeof...( Cs ) ) >= sizeof...( Cs ) ) { if( istring_equal< Cs... >( in.current() ) ) { - bump_help< result_on_found::success, Input, char, Cs... >( in, sizeof...( Cs ) ); + bump_help< result_on_found::success, ParseInput, char, Cs... >( in, sizeof...( Cs ) ); return true; } } @@ -65,7 +65,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< char... Cs > - inline constexpr bool skip_control< istring< Cs... > > = true; + inline constexpr bool enable_control< istring< Cs... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp b/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp index 490a8c7335c53022c7f63e4d56960e3c863bb2c0..416b53d006beb875cf725d25649ceaf8014f26b1 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ITERATOR_HPP @@ -12,20 +12,18 @@ namespace TAO_PEGTL_NAMESPACE::internal { struct iterator { - iterator() noexcept = default; + iterator() = default; explicit iterator( const char* in_data ) noexcept : data( in_data ) - { - } + {} iterator( const char* in_data, const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line ) noexcept : data( in_data ), byte( in_byte ), line( in_line ), byte_in_line( in_byte_in_line ) - { - } + {} iterator( const iterator& ) = default; iterator( iterator&& ) = default; diff --git a/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp index d510f9c2f00f1de22d23bea35beb7d64a30f9a40..2c08186e570ddef4a01f394fc549e17ff81e548b 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_LF_CRLF_EOL_HPP @@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal { static constexpr int ch = '\n'; - template< typename Input > - [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 2 ) ) ) + template< typename ParseInput > + [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 2 ) ) ) { eol_pair p = { false, in.size( 2 ) }; if( p.second ) { diff --git a/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp index 439ba51d01aedc88a409d7a5837a5a493ddce42c..9eee34ebf0777cd1ba25e82ec82c9bfcddb4cab3 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_LF_EOL_HPP @@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal { static constexpr int ch = '\n'; - template< typename Input > - [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 1 ) ) ) + template< typename ParseInput > + [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 1 ) ) ) { eol_pair p = { false, in.size( 1 ) }; if( p.second ) { diff --git a/packages/PEGTL/include/tao/pegtl/internal/list.hpp b/packages/PEGTL/include/tao/pegtl/internal/list.hpp index 83d87de1f25c7e22f88aa66169f3db2c67ff5f74..7a69d4c78ee0889628868f6f80db53e298d62b38 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/list.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/list.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_LIST_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/list_must.hpp b/packages/PEGTL/include/tao/pegtl/internal/list_must.hpp index 2c5a617cc04773b9616594383eee68715864f5cf..545ef6c19e046074f93bd8969a78a83b2351ef76 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/list_must.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/list_must.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_LIST_MUST_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp b/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp index 26b16c395197db06e2d391d8b4bf10a956061cfd..05d4ade59e940bbd03fa18d47f81eb22890d80f4 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_LIST_TAIL_HPP @@ -6,14 +6,16 @@ #include "../config.hpp" -#include "list.hpp" #include "opt.hpp" #include "seq.hpp" +#include "star.hpp" + +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename Rule, typename Sep > - using list_tail = seq< list< Rule, Sep >, opt< Sep > >; + using list_tail = seq< Rule, star< Sep, Rule >, opt< Sep > >; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp b/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp index 28f2f4394ad03173044ca9ed71f398cbb5416c63..e6a43294cdd03707830c5e07fd36f605c1ba4322 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_LIST_TAIL_PAD_HPP @@ -15,7 +15,7 @@ namespace TAO_PEGTL_NAMESPACE::internal { template< typename Rule, typename Sep, typename Pad > - using list_tail_pad = seq< list< Rule, pad< Sep, Pad > >, opt< star< Pad >, Sep > >; + using list_tail_pad = seq< Rule, star< pad< Sep, Pad >, Rule >, opt< star< Pad >, Sep > >; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/marker.hpp b/packages/PEGTL/include/tao/pegtl/internal/marker.hpp index 2834be3723659038a57cc552b2bb06dd2982ec36..27d4c0cf08e42cccac3502b93685251ce2556fa1 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/marker.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/marker.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_MARKER_HPP @@ -16,8 +16,7 @@ namespace TAO_PEGTL_NAMESPACE::internal static constexpr rewind_mode next_rewind_mode = M; explicit marker( const Iterator& /*unused*/ ) noexcept - { - } + {} marker( const marker& ) = delete; marker( marker&& ) = delete; @@ -42,8 +41,7 @@ namespace TAO_PEGTL_NAMESPACE::internal explicit marker( Iterator& i ) noexcept : m_saved( i ), m_input( &i ) - { - } + {} marker( const marker& ) = delete; marker( marker&& ) = delete; diff --git a/packages/PEGTL/include/tao/pegtl/internal/minus.hpp b/packages/PEGTL/include/tao/pegtl/internal/minus.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f928371623e96a086bc5b49eb30df3da9be47bde --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/internal/minus.hpp @@ -0,0 +1,21 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_INTERNAL_MINUS_HPP +#define TAO_PEGTL_INTERNAL_MINUS_HPP + +#include "../config.hpp" + +#include "eof.hpp" +#include "not_at.hpp" +#include "rematch.hpp" +#include "seq.hpp" + +namespace TAO_PEGTL_NAMESPACE::internal +{ + template< typename M, typename S > + using minus = rematch< M, not_at< S, eof > >; + +} // namespace TAO_PEGTL_NAMESPACE::internal + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp index c4e33d16e6a5501ce269ded84d3344159f99c027..0e3e51127f48a7ef7e6162b3bcb9ed2ec051193a 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_MISSING_APPLY_HPP @@ -12,9 +12,9 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Control, template< typename... > class Action, - typename Input, + typename ParseInput, typename... States > - void missing_apply( Input& in, States&&... st ) + void missing_apply( ParseInput& in, States&&... st ) { auto m = in.template mark< rewind_mode::required >(); (void)Control::template apply< Action >( m.iterator(), in, st... ); diff --git a/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp index db58f5d6f8a738c2c839c3e1e2478390cb9b934b..345e50f6e9ec3dce59f0fec4fc0340c48d9aeb86 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_MISSING_APPLY0_HPP @@ -11,9 +11,9 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Control, template< typename... > class Action, - typename Input, + typename ParseInput, typename... States > - void missing_apply0( Input& in, States&&... st ) + void missing_apply0( ParseInput& in, States&&... st ) { (void)Control::template apply0< Action >( in, st... ); } diff --git a/packages/PEGTL/include/tao/pegtl/internal/must.hpp b/packages/PEGTL/include/tao/pegtl/internal/must.hpp index f4e0902160e50a21b41da00b8f8f933352e43c83..4cb6454be7c60efd48e115a95de44ed07e770051 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/must.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/must.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_MUST_HPP @@ -6,13 +6,13 @@ #include "../config.hpp" -#include "raise.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" +#include "seq.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -21,22 +21,13 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename... Rules > struct must - { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + : seq< must< Rules >... > + {}; - template< apply_mode A, - rewind_mode M, - template< typename... > - class Action, - template< typename... > - class Control, - typename Input, - typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) - { - return ( Control< must< Rules > >::template match< A, M, Action, Control >( in, st... ) && ... ); - } - }; + template<> + struct must<> + : success + {}; // While in theory the implementation for a single rule could // be simplified to must< Rule > = sor< Rule, raise< Rule > >, this @@ -45,7 +36,8 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Rule > struct must< Rule > { - using analyze_t = typename Rule::analyze_t; + using rule_t = must; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode, @@ -53,19 +45,19 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { if( !Control< Rule >::template match< A, rewind_mode::dontcare, Action, Control >( in, st... ) ) { - (void)raise< Rule >::template match< A, rewind_mode::dontcare, Action, Control >( in, st... ); + Control< Rule >::raise( static_cast< const ParseInput& >( in ), st... ); } return true; } }; template< typename... Rules > - inline constexpr bool skip_control< must< Rules... > > = true; + inline constexpr bool enable_control< must< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp b/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp index 0ab7fcf848d3d282db0e9ced3c88d10fac23b198..09ba3c5eb089c61d27171cace08444b4e6b9a53e 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_NOT_AT_HPP @@ -6,29 +6,31 @@ #include "../config.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "enable_control.hpp" +#include "failure.hpp" +#include "seq.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename... Rules > - struct not_at; + struct not_at + : not_at< seq< Rules... > > + {}; template<> struct not_at<> - : trivial< false > - { - }; + : failure + {}; - template< typename... Rules > - struct not_at + template< typename Rule > + struct not_at< Rule > { - using analyze_t = analysis::generic< analysis::rule_type::opt, Rules... >; + using rule_t = not_at; + using subs_t = type_list< Rule >; template< apply_mode, rewind_mode, @@ -36,17 +38,17 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { const auto m = in.template mark< rewind_mode::required >(); - return !( Control< Rules >::template match< apply_mode::nothing, rewind_mode::active, Action, Control >( in, st... ) && ... ); + return !Control< Rule >::template match< apply_mode::nothing, rewind_mode::active, Action, Control >( in, st... ); } }; template< typename... Rules > - inline constexpr bool skip_control< not_at< Rules... > > = true; + inline constexpr bool enable_control< not_at< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/one.hpp b/packages/PEGTL/include/tao/pegtl/internal/one.hpp index 451140d036a555e0754d9573098df5f2d42a37e5..65bc2e1236d109bcf4637f95f5c8e4c81dea8b75 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/one.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/one.hpp @@ -1,70 +1,54 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_ONE_HPP #define TAO_PEGTL_INTERNAL_ONE_HPP -#include <algorithm> -#include <utility> +#include <cstddef> #include "../config.hpp" +#include "any.hpp" #include "bump_help.hpp" +#include "enable_control.hpp" +#include "failure.hpp" #include "result_on_found.hpp" -#include "skip_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { - template< typename Char > - [[nodiscard]] bool contains( const Char c, const std::initializer_list< Char >& l ) noexcept - { - return std::find( l.begin(), l.end(), c ) != l.end(); - } - template< result_on_found R, typename Peek, typename Peek::data_t... Cs > struct one { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = one; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) ) { - if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) { - if( const auto t = Peek::peek( in, s ) ) { - if( contains( t.data, { Cs... } ) == bool( R ) ) { - bump_help< R, Input, typename Peek::data_t, Cs... >( in, t.size ); - return true; - } + if( const auto t = Peek::peek( in ) ) { + if( ( ( t.data == Cs ) || ... ) == bool( R ) ) { + bump_help< R, ParseInput, typename Peek::data_t, Cs... >( in, t.size ); + return true; } } return false; } }; - template< result_on_found R, typename Peek, typename Peek::data_t C > - struct one< R, Peek, C > - { - using analyze_t = analysis::generic< analysis::rule_type::any >; + template< typename Peek > + struct one< result_on_found::success, Peek > + : failure + {}; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) ) - { - if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) { - if( const auto t = Peek::peek( in, s ) ) { - if( ( t.data == C ) == bool( R ) ) { - bump_help< R, Input, typename Peek::data_t, C >( in, t.size ); - return true; - } - } - } - return false; - } - }; + template< typename Peek > + struct one< result_on_found::failure, Peek > + : any< Peek > + {}; template< result_on_found R, typename Peek, typename Peek::data_t... Cs > - inline constexpr bool skip_control< one< R, Peek, Cs... > > = true; + inline constexpr bool enable_control< one< R, Peek, Cs... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/opt.hpp b/packages/PEGTL/include/tao/pegtl/internal/opt.hpp index df6da2d222c3c20540c262f9b9a8c3fdecab5dae..9f25c5038ef7e87894398c778186fdf18f04e758 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/opt.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/opt.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_OPT_HPP @@ -8,31 +8,31 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename... Rules > - struct opt; + struct opt + : opt< seq< Rules... > > + {}; template<> struct opt<> - : trivial< true > - { - }; + : success + {}; - template< typename... Rules > - struct opt + template< typename Rule > + struct opt< Rule > { - using analyze_t = analysis::generic< analysis::rule_type::opt, Rules... >; + using rule_t = opt; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode, @@ -40,17 +40,17 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - (void)duseltronik< seq< Rules... >, A, rewind_mode::required, Action, Control >::match( in, st... ); + (void)Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ); return true; } }; template< typename... Rules > - inline constexpr bool skip_control< opt< Rules... > > = true; + inline constexpr bool enable_control< opt< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/pad.hpp b/packages/PEGTL/include/tao/pegtl/internal/pad.hpp index db23e38a4565e228d7986a5a77bccc814be23991..c84f74135afb1d3334e1e41bf54101d27cb300a1 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/pad.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/pad.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_PAD_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/pad_opt.hpp b/packages/PEGTL/include/tao/pegtl/internal/pad_opt.hpp index 2a14a535490b6fbe054fcae8a138cdda7ecc285d..aa965c4c26ce6cb131b7c7c69064488c79b20122 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/pad_opt.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/pad_opt.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_PAD_OPT_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp b/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp index 8383698d4f5b51fe852e157d74e9b00242052462..85f1b4dbe022986634404ab6e353fccb6f86d34b 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_PEEK_CHAR_HPP @@ -17,12 +17,12 @@ namespace TAO_PEGTL_NAMESPACE::internal using data_t = char; using pair_t = input_pair< char >; - static constexpr std::size_t min_input_size = 1; - static constexpr std::size_t max_input_size = 1; - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ = 1 ) noexcept + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) ) { + if( in.empty() ) { + return { 0, 0 }; + } return { in.peek_char(), 1 }; } }; diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint8.hpp b/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint8.hpp deleted file mode 100644 index ef50097e4958fcfcc88e3e4477c8843f430abca6..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint8.hpp +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_INTERNAL_PEEK_MASK_UINT8_HPP -#define TAO_PEGTL_INTERNAL_PEEK_MASK_UINT8_HPP - -#include <cstddef> -#include <cstdint> - -#include "../config.hpp" - -#include "input_pair.hpp" - -namespace TAO_PEGTL_NAMESPACE::internal -{ - template< std::uint8_t M > - struct peek_mask_uint8 - { - using data_t = std::uint8_t; - using pair_t = input_pair< std::uint8_t >; - - static constexpr std::size_t min_input_size = 1; - static constexpr std::size_t max_input_size = 1; - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ = 1 ) noexcept - { - return { std::uint8_t( in.peek_uint8() & M ), 1 }; - } - }; - -} // namespace TAO_PEGTL_NAMESPACE::internal - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_uint8.hpp b/packages/PEGTL/include/tao/pegtl/internal/peek_uint8.hpp deleted file mode 100644 index d5f78af62e99004f6333444902f2c0c837d8b0f9..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_uint8.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_INTERNAL_PEEK_UINT8_HPP -#define TAO_PEGTL_INTERNAL_PEEK_UINT8_HPP - -#include <cstddef> -#include <cstdint> - -#include "../config.hpp" - -#include "input_pair.hpp" - -namespace TAO_PEGTL_NAMESPACE::internal -{ - struct peek_uint8 - { - using data_t = std::uint8_t; - using pair_t = input_pair< std::uint8_t >; - - static constexpr std::size_t min_input_size = 1; - static constexpr std::size_t max_input_size = 1; - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ = 1 ) noexcept - { - return { in.peek_uint8(), 1 }; - } - }; - -} // namespace TAO_PEGTL_NAMESPACE::internal - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp b/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp index aa8a617b7b78d31707f17ea7314d90d58b6d08d4..8f1e5a991ddb42d07494c821fe5d504856d56ade 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_PEEK_UTF8_HPP @@ -15,26 +15,25 @@ namespace TAO_PEGTL_NAMESPACE::internal using data_t = char32_t; using pair_t = input_pair< char32_t >; - static constexpr std::size_t min_input_size = 1; - static constexpr std::size_t max_input_size = 4; - - template< typename Input > - [[nodiscard]] static pair_t peek( const Input& in, const std::size_t s ) noexcept + template< typename ParseInput > + [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) ) { - char32_t c0 = in.peek_uint8(); - + if( in.empty() ) { + return { 0, 0 }; + } + const char32_t c0 = in.peek_uint8(); if( ( c0 & 0x80 ) == 0 ) { return { c0, 1 }; } - return peek_impl( in, c0, s ); + return peek_impl( in, c0 ); } private: - template< typename Input > - [[nodiscard]] static pair_t peek_impl( const Input& in, char32_t c0, const std::size_t s ) noexcept + template< typename ParseInput > + [[nodiscard]] static pair_t peek_impl( ParseInput& in, char32_t c0 ) noexcept( noexcept( in.size( 4 ) ) ) { if( ( c0 & 0xE0 ) == 0xC0 ) { - if( s >= 2 ) { + if( in.size( 2 ) >= 2 ) { const char32_t c1 = in.peek_uint8( 1 ); if( ( c1 & 0xC0 ) == 0x80 ) { c0 &= 0x1F; @@ -47,7 +46,7 @@ namespace TAO_PEGTL_NAMESPACE::internal } } else if( ( c0 & 0xF0 ) == 0xE0 ) { - if( s >= 3 ) { + if( in.size( 3 ) >= 3 ) { const char32_t c1 = in.peek_uint8( 1 ); const char32_t c2 = in.peek_uint8( 2 ); if( ( ( c1 & 0xC0 ) == 0x80 ) && ( ( c2 & 0xC0 ) == 0x80 ) ) { @@ -63,7 +62,7 @@ namespace TAO_PEGTL_NAMESPACE::internal } } else if( ( c0 & 0xF8 ) == 0xF0 ) { - if( s >= 4 ) { + if( in.size( 4 ) >= 4 ) { const char32_t c1 = in.peek_uint8( 1 ); const char32_t c2 = in.peek_uint8( 2 ); const char32_t c3 = in.peek_uint8( 3 ); diff --git a/packages/PEGTL/include/tao/pegtl/internal/pegtl_string.hpp b/packages/PEGTL/include/tao/pegtl/internal/pegtl_string.hpp index b523d66ca77d05182c5aad5f9c6774b96a82a978..6440e97c94618333bf2e211bdc960d71de8d1cad 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/pegtl_string.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/pegtl_string.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_PEGTL_STRING_HPP @@ -51,7 +51,7 @@ namespace TAO_PEGTL_NAMESPACE::internal #define TAO_PEGTL_INTERNAL_EXPAND( ... ) __VA_ARGS__ #define TAO_PEGTL_INTERNAL_STRING_AT( S, x, n ) \ - TAO_PEGTL_NAMESPACE::internal::string_at< S, ( 0##n < sizeof( x ) ) ? ( x )[ 0##n ] : 0, ( 0##n < sizeof( x ) - 1 ) >::type + TAO_PEGTL_NAMESPACE::internal::string_at< S, ( 0##n < ( sizeof( x ) / sizeof( char ) ) ) ? ( x )[ 0##n ] : 0, ( 0##n < ( sizeof( x ) / sizeof( char ) ) - 1 ) >::type #define TAO_PEGTL_INTERNAL_JOIN_8( M, S, x, n ) \ TAO_PEGTL_NAMESPACE::internal::string_join< TAO_PEGTL_INTERNAL_DEFER( M )( S, x, n##0 ), \ diff --git a/packages/PEGTL/include/tao/pegtl/internal/plus.hpp b/packages/PEGTL/include/tao/pegtl/internal/plus.hpp index 815d2beab2a7aab73180a68c7ec44b0d0bda14e1..82e191d8b755f07b22d7bf1841030eadad6f6a66 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/plus.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/plus.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_PLUS_HPP @@ -8,16 +8,12 @@ #include "../config.hpp" -#include "duseltronik.hpp" -#include "opt.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" -#include "star.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -28,8 +24,14 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Rule, typename... Rules > struct plus + : plus< seq< Rule, Rules... > > + {}; + + template< typename Rule > + struct plus< Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rule, Rules..., opt< plus > >; + using rule_t = plus; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode M, @@ -37,16 +39,21 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - return seq< Rule, Rules... >::template match< A, M, Action, Control >( in, st... ) && star< Rule, Rules... >::template match< A, M, Action, Control >( in, st... ); + if( Control< Rule >::template match< A, M, Action, Control >( in, st... ) ) { + while( Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) { + } + return true; + } + return false; } }; template< typename Rule, typename... Rules > - inline constexpr bool skip_control< plus< Rule, Rules... > > = true; + inline constexpr bool enable_control< plus< Rule, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/raise.hpp b/packages/PEGTL/include/tao/pegtl/internal/raise.hpp index 356ffcbd7de76f8769bbbb59bc6b02800a0cfc5d..a84c92a894c2a6cdcdecf319548a8f979dc2cc8e 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/raise.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/raise.hpp @@ -1,52 +1,43 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_RAISE_HPP #define TAO_PEGTL_INTERNAL_RAISE_HPP -#include <cstdlib> #include <stdexcept> -#include <type_traits> #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" -#include "../analysis/generic.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename T > struct raise { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = raise; + using subs_t = empty_list; -#if defined( _MSC_VER ) -#pragma warning( push ) -#pragma warning( disable : 4702 ) -#endif template< apply_mode, rewind_mode, template< typename... > class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[noreturn]] static bool match( ParseInput& in, States&&... st ) { - Control< T >::raise( static_cast< const Input& >( in ), st... ); - throw std::logic_error( "code should be unreachable: Control< T >::raise() did not throw an exception" ); // NOLINT, LCOV_EXCL_LINE -#if defined( _MSC_VER ) -#pragma warning( pop ) -#endif + Control< T >::raise( static_cast< const ParseInput& >( in ), st... ); } }; template< typename T > - inline constexpr bool skip_control< raise< T > > = true; + inline constexpr bool enable_control< raise< T > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/range.hpp b/packages/PEGTL/include/tao/pegtl/internal/range.hpp index 2780377bbedf83a91128d6ac3cd2aa43c90f3b4b..e956b709ca2557018ac8258753d2dd2a9f06f9d8 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/range.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/range.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_RANGE_HPP @@ -6,45 +6,50 @@ #include "../config.hpp" +#include "enable_control.hpp" +#include "one.hpp" #include "result_on_found.hpp" -#include "skip_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi > struct range { - static_assert( Lo <= Hi, "invalid range detected" ); + using rule_t = range; + using subs_t = empty_list; - using analyze_t = analysis::generic< analysis::rule_type::any >; + static_assert( Lo < Hi, "invalid range" ); template< int Eol > static constexpr bool can_match_eol = ( ( ( Lo <= Eol ) && ( Eol <= Hi ) ) == bool( R ) ); - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) ) { - if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) { - if( const auto t = Peek::peek( in, s ) ) { - if( ( ( Lo <= t.data ) && ( t.data <= Hi ) ) == bool( R ) ) { - if constexpr( can_match_eol< Input::eol_t::ch > ) { - in.bump( t.size ); - } - else { - in.bump_in_this_line( t.size ); - } - return true; + if( const auto t = Peek::peek( in ) ) { + if( ( ( Lo <= t.data ) && ( t.data <= Hi ) ) == bool( R ) ) { + if constexpr( can_match_eol< ParseInput::eol_t::ch > ) { + in.bump( t.size ); } + else { + in.bump_in_this_line( t.size ); + } + return true; } } return false; } }; + template< result_on_found R, typename Peek, typename Peek::data_t C > + struct range< R, Peek, C, C > + : one< R, Peek, C > + {}; + template< result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi > - inline constexpr bool skip_control< range< R, Peek, Lo, Hi > > = true; + inline constexpr bool enable_control< range< R, Peek, Lo, Hi > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp b/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp index f815aceb6b24d4ac979ed02c47f938c603b020ee..a26b45539ef196493b1aa01887fe87153afc581e 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_RANGES_HPP @@ -6,10 +6,12 @@ #include "../config.hpp" +#include "enable_control.hpp" +#include "failure.hpp" +#include "one.hpp" #include "range.hpp" -#include "skip_control.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -54,25 +56,24 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Peek, typename Peek::data_t... Cs > struct ranges { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = ranges; + using subs_t = empty_list; template< int Eol > static constexpr bool can_match_eol = ranges_impl< Eol, typename Peek::data_t, Cs... >::can_match_eol; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) ) { - if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) { - if( const auto t = Peek::peek( in, s ) ) { - if( ranges_impl< Input::eol_t::ch, typename Peek::data_t, Cs... >::match( t.data ) ) { - if constexpr( can_match_eol< Input::eol_t::ch > ) { - in.bump( t.size ); - } - else { - in.bump_in_this_line( t.size ); - } - return true; + if( const auto t = Peek::peek( in ) ) { + if( ranges_impl< ParseInput::eol_t::ch, typename Peek::data_t, Cs... >::match( t.data ) ) { + if constexpr( can_match_eol< ParseInput::eol_t::ch > ) { + in.bump( t.size ); } + else { + in.bump_in_this_line( t.size ); + } + return true; } } return false; @@ -82,11 +83,20 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi > struct ranges< Peek, Lo, Hi > : range< result_on_found::success, Peek, Lo, Hi > - { - }; + {}; + + template< typename Peek, typename Peek::data_t C > + struct ranges< Peek, C > + : one< result_on_found::success, Peek, C > + {}; + + template< typename Peek > + struct ranges< Peek > + : failure + {}; template< typename Peek, typename Peek::data_t... Cs > - inline constexpr bool skip_control< ranges< Peek, Cs... > > = true; + inline constexpr bool enable_control< ranges< Peek, Cs... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp b/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp index 5d713266bc0747151e2999b9509ea3b103c47bfd..eefe9283b0a6b34514d6955576d1e73951a44656 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_REMATCH_HPP @@ -6,11 +6,12 @@ #include "../config.hpp" -#include "skip_control.hpp" +#include "enable_control.hpp" #include "../apply_mode.hpp" #include "../memory_input.hpp" #include "../rewind_mode.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -20,7 +21,8 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Head > struct rematch< Head > { - using analyze_t = typename Head::analyze_t; + using rule_t = rematch; + using subs_t = type_list< Head >; template< apply_mode A, rewind_mode M, @@ -28,9 +30,9 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { return Control< Head >::template match< A, M, Action, Control >( in, st... ); } @@ -39,7 +41,8 @@ namespace TAO_PEGTL_NAMESPACE::internal template< typename Head, typename Rule, typename... Rules > struct rematch< Head, Rule, Rules... > { - using analyze_t = typename Head::analyze_t; // NOTE: Rule and Rules are ignored for analyze(). + using rule_t = rematch; + using subs_t = type_list< Head, Rule, Rules... >; template< apply_mode A, rewind_mode, @@ -47,14 +50,14 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< rewind_mode::required >(); if( Control< Head >::template match< A, rewind_mode::active, Action, Control >( in, st... ) ) { - memory_input< Input::tracking_mode_v, typename Input::eol_t, typename Input::source_t > i2( m.iterator(), in.current(), in.source() ); + memory_input< ParseInput::tracking_mode_v, typename ParseInput::eol_t, typename ParseInput::source_t > i2( m.iterator(), in.current(), in.source() ); return m( ( Control< Rule >::template match< A, rewind_mode::active, Action, Control >( i2, st... ) && ... && ( i2.restart( m ), Control< Rules >::template match< A, rewind_mode::active, Action, Control >( i2, st... ) ) ) ); } return false; @@ -62,7 +65,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< typename Head, typename... Rules > - inline constexpr bool skip_control< rematch< Head, Rules... > > = true; + inline constexpr bool enable_control< rematch< Head, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/rep.hpp b/packages/PEGTL/include/tao/pegtl/internal/rep.hpp index 782929da70ff9c4830214ff64a510e6536e450eb..1b7bc8649b21128a031bd9c092931fed2086e04f 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/rep.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/rep.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_REP_HPP @@ -6,35 +6,36 @@ #include "../config.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "enable_control.hpp" +#include "seq.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/counted.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { - template< unsigned Num, typename... Rules > - struct rep; + template< unsigned Cnt, typename... Rules > + struct rep + : rep< Cnt, seq< Rules... > > + {}; - template< unsigned Num > - struct rep< Num > - : trivial< true > - { - }; + template< unsigned Cnt > + struct rep< Cnt > + : success + {}; - template< typename Rule, typename... Rules > - struct rep< 0, Rule, Rules... > - : trivial< true > - { - }; + template< typename Rule > + struct rep< 0, Rule > + : success + {}; - template< unsigned Num, typename... Rules > - struct rep + template< unsigned Cnt, typename Rule > + struct rep< Cnt, Rule > { - using analyze_t = analysis::counted< analysis::rule_type::seq, Num, Rules... >; + using rule_t = rep; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode M, @@ -42,15 +43,15 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< M >(); using m_t = decltype( m ); - for( unsigned i = 0; i != Num; ++i ) { - if( !( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) ) { + for( unsigned i = 0; i != Cnt; ++i ) { + if( !Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ) { return false; } } @@ -58,8 +59,8 @@ namespace TAO_PEGTL_NAMESPACE::internal } }; - template< unsigned Num, typename... Rules > - inline constexpr bool skip_control< rep< Num, Rules... > > = true; + template< unsigned Cnt, typename... Rules > + inline constexpr bool enable_control< rep< Cnt, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/rep_min.hpp b/packages/PEGTL/include/tao/pegtl/internal/rep_min.hpp index fe6f6a772822e4f575c276c642c0448c65204945..ecf9bc014432bf927cee11f8a2d58d73c73e2bac 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/rep_min.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/rep_min.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_REP_MIN_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp b/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp index 6264dd17510bb375e9a309bc6a976fd6bc282d79..f153cd10a37e5c39f28d5c91ef689dbd42e381d6 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_REP_MIN_MAX_HPP @@ -8,39 +8,41 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" +#include "failure.hpp" #include "not_at.hpp" #include "seq.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/counted.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< unsigned Min, unsigned Max, typename... Rules > - struct rep_min_max; + struct rep_min_max + : rep_min_max< Min, Max, seq< Rules... > > + { + static_assert( Min <= Max ); + }; template< unsigned Min, unsigned Max > struct rep_min_max< Min, Max > - : trivial< false > + : failure { static_assert( Min <= Max ); }; - template< typename Rule, typename... Rules > - struct rep_min_max< 0, 0, Rule, Rules... > - : not_at< Rule, Rules... > - { - }; + template< typename Rule > + struct rep_min_max< 0, 0, Rule > + : not_at< Rule > + {}; - template< unsigned Min, unsigned Max, typename... Rules > - struct rep_min_max + template< unsigned Min, unsigned Max, typename Rule > + struct rep_min_max< Min, Max, Rule > { - using analyze_t = analysis::counted< analysis::rule_type::seq, Min, Rules... >; + using rule_t = rep_min_max; + using subs_t = type_list< Rule >; static_assert( Min <= Max ); @@ -50,29 +52,29 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< M >(); using m_t = decltype( m ); for( unsigned i = 0; i != Min; ++i ) { - if( !( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) ) { + if( !Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ) { return false; } } for( unsigned i = Min; i != Max; ++i ) { - if( !duseltronik< seq< Rules... >, A, rewind_mode::required, Action, Control >::match( in, st... ) ) { + if( !Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) { return m( true ); } } - return m( duseltronik< not_at< Rules... >, A, m_t::next_rewind_mode, Action, Control >::match( in, st... ) ); // NOTE that not_at<> will always rewind. + return m( Control< not_at< Rule > >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ); // NOTE that not_at<> will always rewind. } }; template< unsigned Min, unsigned Max, typename... Rules > - inline constexpr bool skip_control< rep_min_max< Min, Max, Rules... > > = true; + inline constexpr bool enable_control< rep_min_max< Min, Max, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp b/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp index 4df310d24e9aee4b29dc54291c98359b989d9fd2..ea69ee5636c07ca7554e44e382bd23359f7d7fa2 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_REP_OPT_HPP @@ -6,21 +6,36 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< unsigned Max, typename... Rules > struct rep_opt + : rep_opt< Max, seq< Rules... > > + {}; + + template< unsigned Max > + struct rep_opt< Max > + : success + {}; + + template< typename... Rules > + struct rep_opt< 0, Rules... > + : success + {}; + + template< unsigned Max, typename Rule > + struct rep_opt< Max, Rule > { - using analyze_t = analysis::generic< analysis::rule_type::opt, Rules... >; + using rule_t = rep_opt; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode, @@ -28,18 +43,18 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - for( unsigned i = 0; ( i != Max ) && duseltronik< seq< Rules... >, A, rewind_mode::required, Action, Control >::match( in, st... ); ++i ) { + for( unsigned i = 0; ( i != Max ) && Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ); ++i ) { } return true; } }; template< unsigned Max, typename... Rules > - inline constexpr bool skip_control< rep_opt< Max, Rules... > > = true; + inline constexpr bool enable_control< rep_opt< Max, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/require.hpp b/packages/PEGTL/include/tao/pegtl/internal/require.hpp index b746feff062a1f8310901ccd96ed729e057ed77e..e6d6b0c9f8fe3ec545d69b43a2d666bce4cf405e 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/require.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/require.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_REQUIRE_HPP @@ -6,10 +6,10 @@ #include "../config.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "enable_control.hpp" +#include "success.hpp" -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -18,24 +18,24 @@ namespace TAO_PEGTL_NAMESPACE::internal template<> struct require< 0 > - : trivial< true > - { - }; + : success + {}; template< unsigned Amount > struct require { - using analyze_t = analysis::generic< analysis::rule_type::opt >; + using rule_t = require; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) ) { return in.size( Amount ) >= Amount; } }; template< unsigned Amount > - inline constexpr bool skip_control< require< Amount > > = true; + inline constexpr bool enable_control< require< Amount > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/result_on_found.hpp b/packages/PEGTL/include/tao/pegtl/internal/result_on_found.hpp index e2ed0a63b95349d9a51f228196790e098566052d..492ec212d2fce3a8b0adfe258494d32d2edfa9c6 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/result_on_found.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/result_on_found.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_RESULT_ON_FOUND_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/rules.hpp b/packages/PEGTL/include/tao/pegtl/internal/rules.hpp index 613c4eacd8f2b1258ad88a243991077cc2c7674e..2e9554a70ff1b1818043035f29e944f695ddcb6d 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/rules.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/rules.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_RULES_HPP @@ -18,9 +18,11 @@ #include "disable.hpp" #include "discard.hpp" #include "enable.hpp" +#include "enable_control.hpp" #include "eof.hpp" #include "eol.hpp" #include "eolf.hpp" +#include "failure.hpp" #include "identifier.hpp" #include "if_apply.hpp" #include "if_must.hpp" @@ -31,6 +33,7 @@ #include "list_must.hpp" #include "list_tail.hpp" #include "list_tail_pad.hpp" +#include "minus.hpp" #include "must.hpp" #include "not_at.hpp" #include "one.hpp" @@ -48,13 +51,12 @@ #include "rep_opt.hpp" #include "require.hpp" #include "seq.hpp" -#include "skip_control.hpp" #include "sor.hpp" #include "star.hpp" #include "star_must.hpp" #include "state.hpp" #include "string.hpp" -#include "trivial.hpp" +#include "success.hpp" #include "try_catch_type.hpp" #include "until.hpp" diff --git a/packages/PEGTL/include/tao/pegtl/internal/seq.hpp b/packages/PEGTL/include/tao/pegtl/internal/seq.hpp index eccf791e7765b1be6772a1d05241d607a49342a2..aa45dbe3163dff044a805cefa94cf8085155b93c 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/seq.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/seq.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_SEQ_HPP @@ -6,13 +6,12 @@ #include "../config.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "enable_control.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -21,33 +20,14 @@ namespace TAO_PEGTL_NAMESPACE::internal template<> struct seq<> - : trivial< true > - { - }; - - template< typename Rule > - struct seq< Rule > - { - using analyze_t = typename Rule::analyze_t; - - template< apply_mode A, - rewind_mode M, - template< typename... > - class Action, - template< typename... > - class Control, - typename Input, - typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) - { - return Control< Rule >::template match< A, M, Action, Control >( in, st... ); - } - }; + : success + {}; template< typename... Rules > struct seq { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + using rule_t = seq; + using subs_t = type_list< Rules... >; template< apply_mode A, rewind_mode M, @@ -55,18 +35,23 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - auto m = in.template mark< M >(); - using m_t = decltype( m ); - return m( ( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) ); + if constexpr( sizeof...( Rules ) == 1 ) { + return Control< Rules... >::template match< A, M, Action, Control >( in, st... ); + } + else { + auto m = in.template mark< M >(); + using m_t = decltype( m ); + return m( ( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) ); + } } }; template< typename... Rules > - inline constexpr bool skip_control< seq< Rules... > > = true; + inline constexpr bool enable_control< seq< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/sor.hpp b/packages/PEGTL/include/tao/pegtl/internal/sor.hpp index b43a9652775878193dbf4e39f849ac93df5b1bd4..c56bcc2da7a45a08603fd312be5edcc6ba4864c7 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/sor.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/sor.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_SOR_HPP @@ -8,13 +8,12 @@ #include "../config.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "enable_control.hpp" +#include "failure.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -23,20 +22,14 @@ namespace TAO_PEGTL_NAMESPACE::internal template<> struct sor<> - : trivial< false > - { - }; + : failure + {}; template< typename... Rules > struct sor - : sor< std::index_sequence_for< Rules... >, Rules... > - { - }; - - template< std::size_t... Indices, typename... Rules > - struct sor< std::index_sequence< Indices... >, Rules... > { - using analyze_t = analysis::generic< analysis::rule_type::sor, Rules... >; + using rule_t = sor; + using subs_t = type_list< Rules... >; template< apply_mode A, rewind_mode M, @@ -44,16 +37,30 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + std::size_t... Indices, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( std::index_sequence< Indices... > /*unused*/, ParseInput& in, States&&... st ) { return ( Control< Rules >::template match< A, ( ( Indices == ( sizeof...( Rules ) - 1 ) ) ? M : rewind_mode::required ), Action, Control >( in, st... ) || ... ); } + + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) + { + return match< A, M, Action, Control >( std::index_sequence_for< Rules... >(), in, st... ); + } }; template< typename... Rules > - inline constexpr bool skip_control< sor< Rules... > > = true; + inline constexpr bool enable_control< sor< Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/star.hpp b/packages/PEGTL/include/tao/pegtl/internal/star.hpp index e785fa73f12c8ef450caf27d685b07bd51965e7a..f1353ba238f2d6ac0c74ffa89aae834fcdd22db8 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/star.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/star.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_STAR_HPP @@ -8,20 +8,25 @@ #include "../config.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename Rule, typename... Rules > struct star + : star< seq< Rule, Rules... > > + {}; + + template< typename Rule > + struct star< Rule > { - using analyze_t = analysis::generic< analysis::rule_type::opt, Rule, Rules..., star >; + using rule_t = star; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode, @@ -29,18 +34,18 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - while( seq< Rule, Rules... >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) { + while( Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) { } return true; } }; template< typename Rule, typename... Rules > - inline constexpr bool skip_control< star< Rule, Rules... > > = true; + inline constexpr bool enable_control< star< Rule, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/star_must.hpp b/packages/PEGTL/include/tao/pegtl/internal/star_must.hpp index 9852828f4fa07e37b58780749552889787dccfdb..3d276137b5c5e645001ef45f6b48fbfaef0bdf2d 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/star_must.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/star_must.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_STAR_MUST_HPP diff --git a/packages/PEGTL/include/tao/pegtl/internal/state.hpp b/packages/PEGTL/include/tao/pegtl/internal/state.hpp index 76c0f6f4f20bb9fb1858bfe92a869db1f258e90f..0fc6cfc0a8e5ccc3ce851bd6fd4f1c017931feed 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/state.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/state.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_STATE_HPP @@ -6,21 +6,31 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename State, typename... Rules > struct state + : state< State, seq< Rules... > > + {}; + + template< typename State > + struct state< State > + : success + {}; + + template< typename State, typename Rule > + struct state< State, Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + using rule_t = state; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode M, @@ -28,13 +38,13 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - State s( static_cast< const Input& >( in ), st... ); - if( duseltronik< seq< Rules... >, A, M, Action, Control >::match( in, s ) ) { - s.success( static_cast< const Input& >( in ), st... ); + State s( static_cast< const ParseInput& >( in ), st... ); + if( Control< Rule >::template match< A, M, Action, Control >( in, s ) ) { + s.success( static_cast< const ParseInput& >( in ), st... ); return true; } return false; @@ -42,7 +52,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< typename State, typename... Rules > - inline constexpr bool skip_control< state< State, Rules... > > = true; + inline constexpr bool enable_control< state< State, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/string.hpp b/packages/PEGTL/include/tao/pegtl/internal/string.hpp index 9ff22d05415b3197132be26d5e9b024f94a2e9f9..3d2f2c433236af5d1bdb8bd299a3592c74ac0cf3 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/string.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/string.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_STRING_HPP @@ -10,11 +10,11 @@ #include "../config.hpp" #include "bump_help.hpp" +#include "enable_control.hpp" #include "result_on_found.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "success.hpp" -#include "../analysis/counted.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { @@ -28,21 +28,21 @@ namespace TAO_PEGTL_NAMESPACE::internal template<> struct string<> - : trivial< true > - { - }; + : success + {}; template< char... Cs > struct string { - using analyze_t = analysis::counted< analysis::rule_type::any, sizeof...( Cs ) >; + using rule_t = string; + using subs_t = empty_list; - template< typename Input > - [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) ) + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) ) { if( in.size( sizeof...( Cs ) ) >= sizeof...( Cs ) ) { if( unsafe_equals( in.current(), { Cs... } ) ) { - bump_help< result_on_found::success, Input, char, Cs... >( in, sizeof...( Cs ) ); + bump_help< result_on_found::success, ParseInput, char, Cs... >( in, sizeof...( Cs ) ); return true; } } @@ -51,7 +51,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< char... Cs > - inline constexpr bool skip_control< string< Cs... > > = true; + inline constexpr bool enable_control< string< Cs... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/success.hpp b/packages/PEGTL/include/tao/pegtl/internal/success.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e93caff15a4c6c8d356f9a3357e5e8494da98f6e --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/internal/success.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_INTERNAL_SUCCESS_HPP +#define TAO_PEGTL_INTERNAL_SUCCESS_HPP + +#include "../config.hpp" + +#include "enable_control.hpp" + +#include "../type_list.hpp" + +namespace TAO_PEGTL_NAMESPACE::internal +{ + struct success + { + using rule_t = success; + using subs_t = empty_list; + + template< typename ParseInput > + [[nodiscard]] static bool match( ParseInput& /*unused*/ ) noexcept + { + return true; + } + }; + + template<> + inline constexpr bool enable_control< success > = false; + +} // namespace TAO_PEGTL_NAMESPACE::internal + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/trivial.hpp b/packages/PEGTL/include/tao/pegtl/internal/trivial.hpp deleted file mode 100644 index 0fa6bb017d1900e2c2e1a7fd1728ae0c9827d329..0000000000000000000000000000000000000000 --- a/packages/PEGTL/include/tao/pegtl/internal/trivial.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey -// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ - -#ifndef TAO_PEGTL_INTERNAL_TRIVIAL_HPP -#define TAO_PEGTL_INTERNAL_TRIVIAL_HPP - -#include "../config.hpp" - -#include "skip_control.hpp" - -#include "../analysis/counted.hpp" - -namespace TAO_PEGTL_NAMESPACE::internal -{ - template< bool Result > - struct trivial - { - using analyze_t = analysis::counted< analysis::rule_type::any, unsigned( !Result ) >; - - template< typename Input > - [[nodiscard]] static bool match( Input& /*unused*/ ) noexcept - { - return Result; - } - }; - - template< bool Result > - inline constexpr bool skip_control< trivial< Result > > = true; - -} // namespace TAO_PEGTL_NAMESPACE::internal - -#endif diff --git a/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp b/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp index eca0db6917adf1123bb08b7bfad13bacd92b9465..630f3d89e1872e48647fa2e2921a72bb8b0a84e4 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_TRY_CATCH_TYPE_HPP @@ -8,31 +8,31 @@ #include "../config.hpp" -#include "duseltronik.hpp" +#include "enable_control.hpp" #include "seq.hpp" -#include "skip_control.hpp" -#include "trivial.hpp" +#include "success.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename Exception, typename... Rules > - struct try_catch_type; + struct try_catch_type + : try_catch_type< Exception, seq< Rules... > > + {}; template< typename Exception > struct try_catch_type< Exception > - : trivial< true > - { - }; + : success + {}; - template< typename Exception, typename... Rules > - struct try_catch_type + template< typename Exception, typename Rule > + struct try_catch_type< Exception, Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >; + using rule_t = try_catch_type; + using subs_t = type_list< Rule >; template< apply_mode A, rewind_mode M, @@ -40,15 +40,15 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< M >(); using m_t = decltype( m ); try { - return m( duseltronik< seq< Rules... >, A, m_t::next_rewind_mode, Action, Control >::match( in, st... ) ); + return m( Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ); } catch( const Exception& ) { return false; @@ -57,7 +57,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< typename Exception, typename... Rules > - inline constexpr bool skip_control< try_catch_type< Exception, Rules... > > = true; + inline constexpr bool enable_control< try_catch_type< Exception, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/internal/until.hpp b/packages/PEGTL/include/tao/pegtl/internal/until.hpp index c48b6dd32ec6a1c6439cd13afcc7b43895f245ef..f32e23fb38776731f32427c898a81509783dd785 100644 --- a/packages/PEGTL/include/tao/pegtl/internal/until.hpp +++ b/packages/PEGTL/include/tao/pegtl/internal/until.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_INTERNAL_UNTIL_HPP @@ -7,25 +7,28 @@ #include "../config.hpp" #include "bytes.hpp" +#include "enable_control.hpp" #include "eof.hpp" #include "not_at.hpp" -#include "skip_control.hpp" +#include "seq.hpp" #include "star.hpp" #include "../apply_mode.hpp" #include "../rewind_mode.hpp" - -#include "../analysis/generic.hpp" +#include "../type_list.hpp" namespace TAO_PEGTL_NAMESPACE::internal { template< typename Cond, typename... Rules > - struct until; + struct until + : until< Cond, seq< Rules... > > + {}; template< typename Cond > struct until< Cond > { - using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, bytes< 1 > >, Cond >; + using rule_t = until; + using subs_t = type_list< Cond >; template< apply_mode A, rewind_mode M, @@ -33,9 +36,9 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< M >(); @@ -49,10 +52,11 @@ namespace TAO_PEGTL_NAMESPACE::internal } }; - template< typename Cond, typename... Rules > - struct until + template< typename Cond, typename Rule > + struct until< Cond, Rule > { - using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, Rules... >, Cond >; + using rule_t = until; + using subs_t = type_list< Cond, Rule >; template< apply_mode A, rewind_mode M, @@ -60,15 +64,15 @@ namespace TAO_PEGTL_NAMESPACE::internal class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { auto m = in.template mark< M >(); using m_t = decltype( m ); while( !Control< Cond >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) { - if( !( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) ) { + if( !Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ) { return false; } } @@ -77,7 +81,7 @@ namespace TAO_PEGTL_NAMESPACE::internal }; template< typename Cond, typename... Rules > - inline constexpr bool skip_control< until< Cond, Rules... > > = true; + inline constexpr bool enable_control< until< Cond, Rules... > > = false; } // namespace TAO_PEGTL_NAMESPACE::internal diff --git a/packages/PEGTL/include/tao/pegtl/istream_input.hpp b/packages/PEGTL/include/tao/pegtl/istream_input.hpp index 55f559e24c6ce042587899e4549e58bf3e081ae3..d9a967ef91f71a5c9e26b61de282db57bb129b31 100644 --- a/packages/PEGTL/include/tao/pegtl/istream_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/istream_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_ISTREAM_INPUT_HPP @@ -19,10 +19,9 @@ namespace TAO_PEGTL_NAMESPACE : buffer_input< internal::istream_reader, Eol, std::string, Chunk > { template< typename T > - istream_input( std::istream& in_stream, const std::size_t in_maximum, T&& in_source ) // NOLINT + istream_input( std::istream& in_stream, const std::size_t in_maximum, T&& in_source ) : buffer_input< internal::istream_reader, Eol, std::string, Chunk >( std::forward< T >( in_source ), in_maximum, in_stream ) - { - } + {} }; template< typename... Ts > diff --git a/packages/PEGTL/include/tao/pegtl/match.hpp b/packages/PEGTL/include/tao/pegtl/match.hpp index 74058f9979eda58d5a0ad2d6c8bd23e75c892413..77f596b94c23954b5eb294bfe103686d0aae3434 100644 --- a/packages/PEGTL/include/tao/pegtl/match.hpp +++ b/packages/PEGTL/include/tao/pegtl/match.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_MATCH_HPP @@ -19,7 +19,6 @@ #include "internal/has_apply0.hpp" #include "internal/missing_apply.hpp" #include "internal/missing_apply0.hpp" -#include "internal/skip_control.hpp" namespace TAO_PEGTL_NAMESPACE { @@ -30,20 +29,20 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] bool match( Input& in, States&&... st ) + [[nodiscard]] bool match( ParseInput& in, States&&... st ) { - constexpr bool enable_control = !internal::skip_control< Rule >; + constexpr bool enable_control = Control< Rule >::enable; constexpr bool enable_action = enable_control && ( A == apply_mode::action ); - using iterator_t = typename Input::iterator_t; - constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const Input&, States... >::value; - constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const Input&, States... >::value; + using iterator_t = typename ParseInput::iterator_t; + constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const ParseInput&, States... >; + constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const ParseInput&, States... >; constexpr bool has_apply = has_apply_void || has_apply_bool; - constexpr bool has_apply0_void = enable_action && internal::has_apply0< Control< Rule >, void, Action, const Input&, States... >::value; - constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const Input&, States... >::value; + constexpr bool has_apply0_void = enable_action && internal::has_apply0< Control< Rule >, void, Action, const ParseInput&, States... >; + constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const ParseInput&, States... >; constexpr bool has_apply0 = has_apply0_void || has_apply0_bool; static_assert( !( has_apply && has_apply0 ), "both apply() and apply0() defined" ); diff --git a/packages/PEGTL/include/tao/pegtl/memory_input.hpp b/packages/PEGTL/include/tao/pegtl/memory_input.hpp index 1380d9a7967868b74515b78189a65f482089e22a..6c4c8c9a5f21944bbe74b36361126b413d8d93ba 100644 --- a/packages/PEGTL/include/tao/pegtl/memory_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/memory_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_MEMORY_INPUT_HPP @@ -46,8 +46,7 @@ namespace TAO_PEGTL_NAMESPACE m_current( in_begin ), m_end( in_end ), m_source( std::forward< T >( in_source ) ) - { - } + {} template< typename T > memory_input_base( const char* in_begin, const char* in_end, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) @@ -55,8 +54,7 @@ namespace TAO_PEGTL_NAMESPACE m_current( in_begin ), m_end( in_end ), m_source( std::forward< T >( in_source ) ) - { - } + {} memory_input_base( const memory_input_base& ) = delete; memory_input_base( memory_input_base&& ) = delete; @@ -124,15 +122,6 @@ namespace TAO_PEGTL_NAMESPACE m_current.byte_in_line = in_byte_in_line; } - template< rewind_mode M > - void restart( const internal::marker< iterator_t, M >& m ) - { - m_current.data = m.iterator().data; - m_current.byte = m.iterator().byte; - m_current.line = m.iterator().line; - m_current.byte_in_line = m.iterator().byte_in_line; - } - protected: const char* const m_begin; iterator_t m_current; @@ -152,8 +141,7 @@ namespace TAO_PEGTL_NAMESPACE m_current( in_begin.data ), m_end( in_end ), m_source( std::forward< T >( in_source ) ) - { - } + {} template< typename T > memory_input_base( const char* in_begin, const char* in_end, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) @@ -161,8 +149,7 @@ namespace TAO_PEGTL_NAMESPACE m_current( in_begin ), m_end( in_end ), m_source( std::forward< T >( in_source ) ) - { - } + {} memory_input_base( const memory_input_base& ) = delete; memory_input_base( memory_input_base&& ) = delete; @@ -219,12 +206,6 @@ namespace TAO_PEGTL_NAMESPACE m_current = m_begin.data; } - template< rewind_mode M > - void restart( const internal::marker< iterator_t, M >& m ) - { - m_current = m.iterator(); - } - protected: const internal::iterator m_begin; iterator_t m_current; @@ -251,22 +232,19 @@ namespace TAO_PEGTL_NAMESPACE using internal::memory_input_base< P, Eol, Source >::memory_input_base; template< typename T > - memory_input( const char* in_begin, const std::size_t in_size, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) // NOLINT + memory_input( const char* in_begin, const std::size_t in_size, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) : memory_input( in_begin, in_begin + in_size, std::forward< T >( in_source ) ) - { - } + {} template< typename T > memory_input( const std::string& in_string, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) : memory_input( in_string.data(), in_string.size(), std::forward< T >( in_source ) ) - { - } + {} template< typename T > - memory_input( const std::string_view in_string, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) // NOLINT + memory_input( const std::string_view in_string, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) : memory_input( in_string.data(), in_string.size(), std::forward< T >( in_source ) ) - { - } + {} template< typename T > memory_input( std::string&&, T&& ) = delete; @@ -274,14 +252,12 @@ namespace TAO_PEGTL_NAMESPACE template< typename T > memory_input( const char* in_begin, T&& in_source ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) : memory_input( in_begin, std::strlen( in_begin ), std::forward< T >( in_source ) ) - { - } + {} template< typename T > - memory_input( const char* in_begin, const char* in_end, T&& in_source, const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) // NOLINT + memory_input( const char* in_begin, const char* in_end, T&& in_source, const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line ) noexcept( std::is_nothrow_constructible_v< Source, T&& > ) : memory_input( { in_begin, in_byte, in_line, in_byte_in_line }, in_end, std::forward< T >( in_source ) ) - { - } + {} memory_input( const memory_input& ) = delete; memory_input( memory_input&& ) = delete; @@ -326,6 +302,14 @@ namespace TAO_PEGTL_NAMESPACE return this->m_current; } + using internal::memory_input_base< P, Eol, Source >::restart; + + template< rewind_mode M > + void restart( const internal::marker< iterator_t, M >& m ) noexcept + { + iterator() = m.iterator(); + } + using internal::memory_input_base< P, Eol, Source >::position; [[nodiscard]] TAO_PEGTL_NAMESPACE::position position() const @@ -333,13 +317,9 @@ namespace TAO_PEGTL_NAMESPACE return position( iterator() ); } - void discard() const noexcept - { - } + void discard() const noexcept {} - void require( const std::size_t /*unused*/ ) const noexcept - { - } + void require( const std::size_t /*unused*/ ) const noexcept {} template< rewind_mode M > [[nodiscard]] internal::marker< iterator_t, M > mark() noexcept @@ -369,7 +349,7 @@ namespace TAO_PEGTL_NAMESPACE [[nodiscard]] std::string_view line_at( const TAO_PEGTL_NAMESPACE::position& p ) const noexcept { const char* b = begin_of_line( p ); - return std::string_view( b, end_of_line( p ) - b ); + return std::string_view( b, static_cast< std::size_t >( end_of_line( p ) - b ) ); } }; diff --git a/packages/PEGTL/include/tao/pegtl/mmap_input.hpp b/packages/PEGTL/include/tao/pegtl/mmap_input.hpp index 1b9d067d2b65884bf1f515d328fd781160778745..82206dee5ce1e351acd426dcf9a1836b2d511266 100644 --- a/packages/PEGTL/include/tao/pegtl/mmap_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/mmap_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_MMAP_INPUT_HPP @@ -36,8 +36,7 @@ namespace TAO_PEGTL_NAMESPACE explicit mmap_holder( T&& in_filename ) : filename( std::forward< T >( in_filename ) ), data( filename.c_str() ) - { - } + {} mmap_holder( const mmap_holder& ) = delete; mmap_holder( mmap_holder&& ) = delete; @@ -59,8 +58,7 @@ namespace TAO_PEGTL_NAMESPACE explicit mmap_input( T&& in_filename ) : internal::mmap_holder( std::forward< T >( in_filename ) ), memory_input< P, Eol, const char* >( data.begin(), data.end(), filename.c_str() ) - { - } + {} mmap_input( const mmap_input& ) = delete; mmap_input( mmap_input&& ) = delete; diff --git a/packages/PEGTL/include/tao/pegtl/must_if.hpp b/packages/PEGTL/include/tao/pegtl/must_if.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ab15cb6b6c71fbd0f287b3e5edda55c9ded4313e --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/must_if.hpp @@ -0,0 +1,62 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_MUST_IF_HPP +#define TAO_PEGTL_MUST_IF_HPP + +#include "config.hpp" +#include "normal.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + template< typename T, typename Rule, typename = void > + inline constexpr bool raise_on_failure = ( T::template message< Rule > != nullptr ); + + template< typename T, typename Rule > + inline constexpr bool raise_on_failure< T, Rule, decltype( T::template raise_on_failure< Rule >, void() ) > = T::template raise_on_failure< Rule >; + + } // namespace internal + + template< typename T, template< typename... > class Base = normal, bool RequireMessage = true > + struct must_if + { + template< typename Rule > + struct control + : Base< Rule > + { + template< typename ParseInput, typename... States > + static void failure( const ParseInput& in, States&&... st ) noexcept( !internal::raise_on_failure< T, Rule > && noexcept( Base< Rule >::failure( in, st... ) ) ) + { + if constexpr( internal::raise_on_failure< T, Rule > ) { + raise( in, st... ); + } + else { + Base< Rule >::failure( in, st... ); + } + } + + template< typename ParseInput, typename... States > + [[noreturn]] static void raise( const ParseInput& in, States&&... st ) + { + if constexpr( RequireMessage ) { + static_assert( T::template message< Rule > != nullptr ); + } + if constexpr( T::template message< Rule > != nullptr ) { + constexpr const char* p = T::template message< Rule >; + throw parse_error( p, in ); +#if defined( _MSC_VER ) + (void)( (void)st, ... ); +#endif + } + else { + Base< Rule >::raise( in, st... ); + } + } + }; + }; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/normal.hpp b/packages/PEGTL/include/tao/pegtl/normal.hpp index b7b323534139ce3ea97855b1f5324dd1470a5c12..5d7845b99433dd041d51ef05b1740d392f12dab7 100644 --- a/packages/PEGTL/include/tao/pegtl/normal.hpp +++ b/packages/PEGTL/include/tao/pegtl/normal.hpp @@ -1,9 +1,10 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_NORMAL_HPP #define TAO_PEGTL_NORMAL_HPP +#include <string> #include <type_traits> #include <utility> @@ -14,6 +15,7 @@ #include "rewind_mode.hpp" #include "internal/demangle.hpp" +#include "internal/enable_control.hpp" #include "internal/has_match.hpp" namespace TAO_PEGTL_NAMESPACE @@ -21,42 +23,41 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule > struct normal { - template< typename Input, typename... States > - static void start( const Input& /*unused*/, States&&... /*unused*/ ) noexcept - { - } + static constexpr bool enable = internal::enable_control< Rule >; - template< typename Input, typename... States > - static void success( const Input& /*unused*/, States&&... /*unused*/ ) noexcept - { - } + template< typename ParseInput, typename... States > + static void start( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept + {} - template< typename Input, typename... States > - static void failure( const Input& /*unused*/, States&&... /*unused*/ ) noexcept - { - } + template< typename ParseInput, typename... States > + static void success( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept + {} + + template< typename ParseInput, typename... States > + static void failure( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept + {} - template< typename Input, typename... States > - static void raise( const Input& in, States&&... /*unused*/ ) + template< typename ParseInput, typename... States > + [[noreturn]] static void raise( const ParseInput& in, States&&... /*unused*/ ) { - throw parse_error( "parse error matching " + internal::demangle< Rule >(), in ); + throw parse_error( "parse error matching " + std::string( internal::demangle< Rule >() ), in ); } template< template< typename... > class Action, typename Iterator, - typename Input, + typename ParseInput, typename... States > - static auto apply( const Iterator& begin, const Input& in, States&&... st ) noexcept( noexcept( Action< Rule >::apply( std::declval< const typename Input::action_t& >(), st... ) ) ) - -> decltype( Action< Rule >::apply( std::declval< const typename Input::action_t& >(), st... ) ) + static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) noexcept( noexcept( Action< Rule >::apply( std::declval< const typename ParseInput::action_t& >(), st... ) ) ) + -> decltype( Action< Rule >::apply( std::declval< const typename ParseInput::action_t& >(), st... ) ) { - const typename Input::action_t action_input( begin, in ); + const typename ParseInput::action_t action_input( begin, in ); return Action< Rule >::apply( action_input, st... ); } template< template< typename... > class Action, - typename Input, + typename ParseInput, typename... States > - static auto apply0( const Input& /*unused*/, States&&... st ) noexcept( noexcept( Action< Rule >::apply0( st... ) ) ) + static auto apply0( const ParseInput& /*unused*/, States&&... st ) noexcept( noexcept( Action< Rule >::apply0( st... ) ) ) -> decltype( Action< Rule >::apply0( st... ) ) { return Action< Rule >::apply0( st... ); @@ -68,14 +69,14 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... st ) + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) { - if constexpr( internal::has_match_v< Rule, A, M, Action, Control, Input, States... > ) { + if constexpr( internal::has_match< bool, Rule, A, M, Action, Control, ParseInput, States... > ) { return Action< Rule >::template match< Rule, A, M, Action, Control >( in, st... ); } - else { // NOLINT + else { return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... ); } } diff --git a/packages/PEGTL/include/tao/pegtl/nothing.hpp b/packages/PEGTL/include/tao/pegtl/nothing.hpp index 20c23c2b9e1459be88e8a599140ee2a02d466818..6c4b759ce9f5fad6d80c5488707f9cdd2158a8e0 100644 --- a/packages/PEGTL/include/tao/pegtl/nothing.hpp +++ b/packages/PEGTL/include/tao/pegtl/nothing.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_NOTHING_HPP @@ -10,8 +10,7 @@ namespace TAO_PEGTL_NAMESPACE { template< typename Rule > struct nothing - { - }; + {}; using maybe_nothing = nothing< void >; diff --git a/packages/PEGTL/include/tao/pegtl/parse.hpp b/packages/PEGTL/include/tao/pegtl/parse.hpp index d566eaeccfc3e602b6f22d2f5ff00fab8189878c..7d435708a06209082cca146350cd993c218acf70 100644 --- a/packages/PEGTL/include/tao/pegtl/parse.hpp +++ b/packages/PEGTL/include/tao/pegtl/parse.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_PARSE_HPP @@ -13,8 +13,6 @@ #include "parse_error.hpp" #include "rewind_mode.hpp" -#include "internal/action_input.hpp" - namespace TAO_PEGTL_NAMESPACE { template< typename Rule, @@ -22,9 +20,9 @@ namespace TAO_PEGTL_NAMESPACE template< typename... > class Control = normal, apply_mode A = apply_mode::action, rewind_mode M = rewind_mode::required, - typename Input, + typename ParseInput, typename... States > - bool parse( Input&& in, States&&... st ) + bool parse( ParseInput&& in, States&&... st ) { return Control< Rule >::template match< A, M, Action, Control >( in, st... ); } @@ -34,10 +32,10 @@ namespace TAO_PEGTL_NAMESPACE template< typename... > class Control = normal, apply_mode A = apply_mode::action, rewind_mode M = rewind_mode::required, - typename Outer, - typename Input, + typename OuterInput, + typename ParseInput, typename... States > - bool parse_nested( const Outer& oi, Input&& in, States&&... st ) + bool parse_nested( const OuterInput& oi, ParseInput&& in, States&&... st ) { try { return parse< Rule, Action, Control, A, M >( in, st... ); diff --git a/packages/PEGTL/include/tao/pegtl/parse_error.hpp b/packages/PEGTL/include/tao/pegtl/parse_error.hpp index eee0ec686693a02207a230a0a3683ce0eb1afc99..d48f95b830048929c62fbaba1348be9be915b721 100644 --- a/packages/PEGTL/include/tao/pegtl/parse_error.hpp +++ b/packages/PEGTL/include/tao/pegtl/parse_error.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_PARSE_ERROR_HPP @@ -17,28 +17,19 @@ namespace TAO_PEGTL_NAMESPACE { struct parse_error - : public std::runtime_error + : std::runtime_error { template< typename Msg > - parse_error( Msg&& msg, const std::vector< position >& in_positions ) - : std::runtime_error( std::forward< Msg >( msg ) ), - positions( in_positions ) - { - } - - template< typename Msg > - parse_error( Msg&& msg, std::vector< position >&& in_positions ) + parse_error( Msg&& msg, std::vector< position > in_positions ) : std::runtime_error( std::forward< Msg >( msg ) ), positions( std::move( in_positions ) ) - { - } + {} template< typename Msg > parse_error( Msg&& msg, const position& pos ) : std::runtime_error( std::forward< Msg >( msg ) ), positions( 1, pos ) - { - } + {} template< typename Msg > parse_error( Msg&& msg, position&& pos ) @@ -47,11 +38,10 @@ namespace TAO_PEGTL_NAMESPACE positions.emplace_back( std::move( pos ) ); } - template< typename Msg, typename Input > - parse_error( Msg&& msg, const Input& in ) + template< typename Msg, typename ParseInput > + parse_error( Msg&& msg, const ParseInput& in ) : parse_error( std::forward< Msg >( msg ), in.position() ) - { - } + {} std::vector< position > positions; }; diff --git a/packages/PEGTL/include/tao/pegtl/position.hpp b/packages/PEGTL/include/tao/pegtl/position.hpp index c14446f73ed21bb812b403691e2fcb4e2ef0072b..6cdc07bd02077901d81769ab60ff3f573b187190 100644 --- a/packages/PEGTL/include/tao/pegtl/position.hpp +++ b/packages/PEGTL/include/tao/pegtl/position.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_POSITION_HPP @@ -18,14 +18,37 @@ namespace TAO_PEGTL_NAMESPACE { struct position { + position() = delete; + + position( position&& p ) noexcept + : byte( p.byte ), + line( p.line ), + byte_in_line( p.byte_in_line ), + source( std::move( p.source ) ) + {} + + position( const position& ) = default; + + position& operator=( position&& p ) noexcept + { + byte = p.byte; + line = p.line; + byte_in_line = p.byte_in_line; + source = std::move( p.source ); + return *this; + } + + position& operator=( const position& ) = default; + template< typename T > position( const internal::iterator& in_iter, T&& in_source ) : byte( in_iter.byte ), line( in_iter.line ), byte_in_line( in_iter.byte_in_line ), source( std::forward< T >( in_source ) ) - { - } + {} + + ~position() = default; std::size_t byte; std::size_t line; diff --git a/packages/PEGTL/include/tao/pegtl/read_input.hpp b/packages/PEGTL/include/tao/pegtl/read_input.hpp index 72be702fdceb4fd41e8049e9994f272372f51210..224b2e9a75874cbac59aff00dbe95b950b29d241 100644 --- a/packages/PEGTL/include/tao/pegtl/read_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/read_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_READ_INPUT_HPP @@ -24,8 +24,7 @@ namespace TAO_PEGTL_NAMESPACE template< typename T > explicit filename_holder( T&& in_filename ) : filename( std::forward< T >( in_filename ) ) - { - } + {} filename_holder( const filename_holder& ) = delete; filename_holder( filename_holder&& ) = delete; @@ -47,15 +46,13 @@ namespace TAO_PEGTL_NAMESPACE explicit read_input( T&& in_filename ) : internal::filename_holder( std::forward< T >( in_filename ) ), string_input< P, Eol, const char* >( internal::file_reader( filename.c_str() ).read(), filename.c_str() ) - { - } + {} template< typename T > read_input( FILE* in_file, T&& in_filename ) : internal::filename_holder( std::forward< T >( in_filename ) ), string_input< P, Eol, const char* >( internal::file_reader( in_file, filename.c_str() ).read(), filename.c_str() ) - { - } + {} read_input( const read_input& ) = delete; read_input( read_input&& ) = delete; diff --git a/packages/PEGTL/include/tao/pegtl/require_apply.hpp b/packages/PEGTL/include/tao/pegtl/require_apply.hpp index 66d46715dc6c82d25d769318f24a279a31a58e67..0bc78fe660852ed09a96ff819c2071e2188722ac 100644 --- a/packages/PEGTL/include/tao/pegtl/require_apply.hpp +++ b/packages/PEGTL/include/tao/pegtl/require_apply.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_REQUIRE_APPLY_HPP diff --git a/packages/PEGTL/include/tao/pegtl/require_apply0.hpp b/packages/PEGTL/include/tao/pegtl/require_apply0.hpp index af95110b3f8b68c29c4fe78c4f2112d7168dc022..1487ae08cb8abed12d6d49621965df14d9ba15d7 100644 --- a/packages/PEGTL/include/tao/pegtl/require_apply0.hpp +++ b/packages/PEGTL/include/tao/pegtl/require_apply0.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_REQUIRE_APPLY0_HPP diff --git a/packages/PEGTL/include/tao/pegtl/rewind_mode.hpp b/packages/PEGTL/include/tao/pegtl/rewind_mode.hpp index 0d9ad32c0edf7f8f75eace944590cce630ef55f3..dfd21c70ac252ffaff14f0756c298e38f17ffc20 100644 --- a/packages/PEGTL/include/tao/pegtl/rewind_mode.hpp +++ b/packages/PEGTL/include/tao/pegtl/rewind_mode.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_REWIND_MODE_HPP diff --git a/packages/PEGTL/include/tao/pegtl/rules.hpp b/packages/PEGTL/include/tao/pegtl/rules.hpp index 7ec5b8494ea3894adb7ea9cc15221e51c7b3448b..659619c0eda2725b8bf3d6d67ae1fb912ba17249 100644 --- a/packages/PEGTL/include/tao/pegtl/rules.hpp +++ b/packages/PEGTL/include/tao/pegtl/rules.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_RULES_HPP @@ -24,7 +24,8 @@ namespace TAO_PEGTL_NAMESPACE struct discard : internal::discard {}; template< typename... Rules > struct enable : internal::enable< Rules... > {}; struct eof : internal::eof {}; - struct failure : internal::trivial< false > {}; + struct eolf : internal::eolf {}; + struct failure : internal::failure {}; template< typename Rule, typename... Actions > struct if_apply : internal::if_apply< Rule, Actions... > {}; template< typename Cond, typename... Thens > struct if_must : internal::if_must< false, Cond, Thens... > {}; template< typename Cond, typename Then, typename Else > struct if_must_else : internal::if_must_else< Cond, Then, Else > {}; @@ -35,7 +36,7 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule, typename Sep > struct list_must< Rule, Sep, void > : internal::list_must< Rule, Sep > {}; template< typename Rule, typename Sep, typename Pad = void > struct list_tail : internal::list_tail_pad< Rule, Sep, Pad > {}; template< typename Rule, typename Sep > struct list_tail< Rule, Sep, void > : internal::list_tail< Rule, Sep > {}; - template< typename M, typename S > struct minus : internal::rematch< M, internal::not_at< S, internal::eof > > {}; + template< typename M, typename S > struct minus : internal::minus< M, S > {}; template< typename... Rules > struct must : internal::must< Rules... > {}; template< typename... Rules > struct not_at : internal::not_at< Rules... > {}; template< typename... Rules > struct opt : internal::opt< Rules... > {}; @@ -56,9 +57,9 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule, typename... Rules > struct star : internal::star< Rule, Rules... > {}; template< typename Cond, typename... Rules > struct star_must : internal::star_must< Cond, Rules... > {}; template< typename State, typename... Rules > struct state : internal::state< State, Rules... > {}; - struct success : internal::trivial< true > {}; - template< typename... Rules > struct try_catch : internal::try_catch_type< parse_error, Rules... > {}; - template< typename Exception, typename... Rules > struct try_catch_type : internal::try_catch_type< Exception, Rules... > {}; + struct success : internal::success {}; + template< typename... Rules > struct try_catch : internal::seq< internal::try_catch_type< parse_error, Rules... > > {}; + template< typename Exception, typename... Rules > struct try_catch_type : internal::seq< internal::try_catch_type< Exception, Rules... > > {}; template< typename Cond, typename... Rules > struct until : internal::until< Cond, Rules... > {}; // clang-format on diff --git a/packages/PEGTL/include/tao/pegtl/string_input.hpp b/packages/PEGTL/include/tao/pegtl/string_input.hpp index f1b59b1281d268b7534d9392616420dc6ed8aa42..06fec70d670f3554e5f3f167d33416048b81ef41 100644 --- a/packages/PEGTL/include/tao/pegtl/string_input.hpp +++ b/packages/PEGTL/include/tao/pegtl/string_input.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_STRING_INPUT_HPP @@ -23,8 +23,7 @@ namespace TAO_PEGTL_NAMESPACE template< typename T > explicit string_holder( T&& in_data ) : data( std::forward< T >( in_data ) ) - { - } + {} string_holder( const string_holder& ) = delete; string_holder( string_holder&& ) = delete; @@ -46,8 +45,7 @@ namespace TAO_PEGTL_NAMESPACE explicit string_input( V&& in_data, T&& in_source, Ts&&... ts ) : internal::string_holder( std::forward< V >( in_data ) ), memory_input< P, Eol, Source >( data.data(), data.size(), std::forward< T >( in_source ), std::forward< Ts >( ts )... ) - { - } + {} string_input( const string_input& ) = delete; string_input( string_input&& ) = delete; diff --git a/packages/PEGTL/include/tao/pegtl/tracking_mode.hpp b/packages/PEGTL/include/tao/pegtl/tracking_mode.hpp index ba58b5c07761a1a99e74c7b7244a3ad15d299bbe..d2b8ce871b18c9cb51fc6f3f548f339739c86a5d 100644 --- a/packages/PEGTL/include/tao/pegtl/tracking_mode.hpp +++ b/packages/PEGTL/include/tao/pegtl/tracking_mode.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_TRACKING_MODE_HPP diff --git a/packages/PEGTL/include/tao/pegtl/type_list.hpp b/packages/PEGTL/include/tao/pegtl/type_list.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a6bfcdfd34baa871a891478e56cb8684b22030f5 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/type_list.hpp @@ -0,0 +1,46 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_TYPE_LIST_HPP +#define TAO_PEGTL_TYPE_LIST_HPP + +#include <cstddef> + +#include "config.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + template< typename... Ts > + struct type_list + { + static constexpr std::size_t size = sizeof...( Ts ); + }; + + using empty_list = type_list<>; + + template< typename... > + struct type_list_concat; + + template<> + struct type_list_concat<> + { + using type = empty_list; + }; + + template< typename... Ts > + struct type_list_concat< type_list< Ts... > > + { + using type = type_list< Ts... >; + }; + + template< typename... T0s, typename... T1s, typename... Ts > + struct type_list_concat< type_list< T0s... >, type_list< T1s... >, Ts... > + : type_list_concat< type_list< T0s..., T1s... >, Ts... > + {}; + + template< typename... Ts > + using type_list_concat_t = typename type_list_concat< Ts... >::type; + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/include/tao/pegtl/utf8.hpp b/packages/PEGTL/include/tao/pegtl/utf8.hpp index 0f3cb4aea597752d57acc955c51d370ab53b88cc..10db39b39ca022198c16e7a8decb476ebfb1cc4a 100644 --- a/packages/PEGTL/include/tao/pegtl/utf8.hpp +++ b/packages/PEGTL/include/tao/pegtl/utf8.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_UTF8_HPP diff --git a/packages/PEGTL/include/tao/pegtl/version.hpp b/packages/PEGTL/include/tao/pegtl/version.hpp index 6a11e3e0e476fbaee31a0535e23dafc780677d0b..0a78ea4d0fff7d1479895e78c9c2b6844a8c21cd 100644 --- a/packages/PEGTL/include/tao/pegtl/version.hpp +++ b/packages/PEGTL/include/tao/pegtl/version.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_VERSION_HPP diff --git a/packages/PEGTL/include/tao/pegtl/visit.hpp b/packages/PEGTL/include/tao/pegtl/visit.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ad575bd590e87883bae31a46c589321b560b3be3 --- /dev/null +++ b/packages/PEGTL/include/tao/pegtl/visit.hpp @@ -0,0 +1,66 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_VISIT_HPP +#define TAO_PEGTL_VISIT_HPP + +#include <type_traits> + +#include "config.hpp" +#include "type_list.hpp" + +namespace TAO_PEGTL_NAMESPACE +{ + namespace internal + { + template< typename Type, typename... Types > + inline constexpr bool contains = ( std::is_same_v< Type, Types > || ... ); + + template< typename Rules, typename Todo, typename Done > + struct filter + { + using type = Todo; + }; + + template< typename Rule, typename... Rules, typename... Todo, typename... Done > + struct filter< type_list< Rule, Rules... >, type_list< Todo... >, type_list< Done... > > + : filter< type_list< Rules... >, std::conditional_t< contains< Rule, Todo..., Done... >, type_list< Todo... >, type_list< Rule, Todo... > >, type_list< Done... > > + {}; + + template< typename Rules, typename Todo, typename Done > + using filter_t = typename filter< Rules, Todo, Done >::type; + + template< template< typename... > class Func, typename Done, typename... Rules > + struct visitor + { + template< typename... Args > + static void visit( Args&&... args ) + { + ( Func< Rules >::visit( args... ), ... ); + using NextDone = type_list_concat_t< type_list< Rules... >, Done >; + using NextSubs = type_list_concat_t< typename Rules::subs_t... >; + using NextTodo = filter_t< NextSubs, empty_list, NextDone >; + if constexpr( !std::is_same_v< NextTodo, empty_list > ) { + visit_next< NextDone >( NextTodo(), args... ); + } + } + + private: + template< typename NextDone, typename... NextTodo, typename... Args > + static void visit_next( type_list< NextTodo... > /*unused*/, Args&&... args ) + { + visitor< Func, NextDone, NextTodo... >::visit( args... ); + } + }; + + } // namespace internal + + template< typename Rule, template< typename... > class Func, typename... Args > + void visit( Args&&... args ) + { + internal::visitor< Func, empty_list, Rule >::visit( args... ); + } + +} // namespace TAO_PEGTL_NAMESPACE + +#endif diff --git a/packages/PEGTL/src/example/pegtl/CMakeLists.txt b/packages/PEGTL/src/example/pegtl/CMakeLists.txt index 2fed9a883279bf46e9e6178ec8b5a1b5a24ba56a..60518785710ccf34241b761ef4dfef3d6d6c4a52 100644 --- a/packages/PEGTL/src/example/pegtl/CMakeLists.txt +++ b/packages/PEGTL/src/example/pegtl/CMakeLists.txt @@ -12,7 +12,10 @@ set(example_sources indent_aware.cpp json_build.cpp json_count.cpp + json_coverage.cpp json_parse.cpp + json_print_rules.cpp + json_print_sub_rules.cpp lua53_parse.cpp modulus_match.cpp parse_tree.cpp diff --git a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp index 4e019eccbe1112f79937d291a47627e76e97c585..5af83c55112402a143afa902ce883e6b5bf2ce49 100644 --- a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp +++ b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <algorithm> @@ -24,663 +24,697 @@ #endif #include <tao/pegtl.hpp> -#include <tao/pegtl/analyze.hpp> #include <tao/pegtl/contrib/abnf.hpp> +#include <tao/pegtl/contrib/analyze.hpp> #include <tao/pegtl/contrib/parse_tree.hpp> -namespace TAO_PEGTL_NAMESPACE::abnf +namespace TAO_PEGTL_NAMESPACE { - using node_ptr = std::unique_ptr< parse_tree::node >; - - namespace + namespace abnf { - std::string prefix = "tao::pegtl::"; // NOLINT - - std::set< std::string > keywords = { // NOLINT - "alignas", - "alignof", - "and", - "and_eq", - "asm", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "char16_t", - "char32_t", - "class", - "compl", - "const", - "constexpr", - "const_cast", - "continue", - "decltype", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "inline", - "int", - "long", - "mutable", - "namespace", - "new", - "noexcept", - "not", - "not_eq", - "nullptr", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "return", - "short", - "signed", - "sizeof", - "static", - "static_assert", - "static_cast", - "struct", - "switch", - "template", - "this", - "thread_local", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq" - }; - - using rules_t = std::vector< std::string >; - rules_t rules_defined; // NOLINT - rules_t rules; // NOLINT - - // clang-format off - struct one_tag {}; - struct string_tag {}; - struct istring_tag {}; - // clang-format on + using node_ptr = std::unique_ptr< parse_tree::node >; - rules_t::reverse_iterator find_rule( rules_t& r, const std::string& v, const rules_t::reverse_iterator& rbegin ) + namespace { - return std::find_if( rbegin, r.rend(), [&]( const rules_t::value_type& p ) { return TAO_PEGTL_STRCASECMP( p.c_str(), v.c_str() ) == 0; } ); - } - - rules_t::reverse_iterator find_rule( rules_t& r, const std::string& v ) - { - return find_rule( r, v, r.rbegin() ); - } + std::string prefix = "tao::pegtl::"; + + std::set< std::string > keywords = { + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char8_t", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "consteval", + "constexpr", + "constinit", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "return", + "requires", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq" + }; + + using rules_t = std::vector< std::string >; + rules_t rules_defined; + rules_t rules; + + // clang-format off + struct one_tag {}; + struct string_tag {}; + struct istring_tag {}; + // clang-format on + + rules_t::reverse_iterator find_rule( rules_t& r, const std::string& v, const rules_t::reverse_iterator& rbegin ) + { + return std::find_if( rbegin, r.rend(), [&]( const rules_t::value_type& p ) { return TAO_PEGTL_STRCASECMP( p.c_str(), v.c_str() ) == 0; } ); + } - bool append_char( std::string& s, const char c ) - { - if( !s.empty() ) { - s += ", "; + rules_t::reverse_iterator find_rule( rules_t& r, const std::string& v ) + { + return find_rule( r, v, r.rbegin() ); } - s += '\''; - if( c == '\'' || c == '\\' ) { - s += '\\'; + + bool append_char( std::string& s, const char c ) + { + if( !s.empty() ) { + s += ", "; + } + s += '\''; + if( c == '\'' || c == '\\' ) { + s += '\\'; + } + s += c; + s += '\''; + return std::isalpha( c ) != 0; } - s += c; - s += '\''; - return std::isalpha( c ) != 0; - } - std::string remove_leading_zeroes( const std::string& v ) - { - const auto pos = v.find_first_not_of( '0' ); - if( pos == std::string::npos ) { - return ""; + std::string remove_leading_zeroes( const std::string& v ) + { + const auto pos = v.find_first_not_of( '0' ); + if( pos == std::string::npos ) { + return ""; + } + return v.substr( pos ); } - return v.substr( pos ); - } - void shift( internal::iterator& it, int delta ) - { - it.data += delta; - it.byte += delta; - it.byte_in_line += delta; - } + void shift( internal::iterator& it, int delta ) + { + it.data += delta; + it.byte += delta; + it.byte_in_line += delta; + } - } // namespace + } // namespace - namespace grammar - { - // ABNF grammar according to RFC 5234, updated by RFC 7405, with - // the following differences: - // - // To form a C++ identifier from a rulename, all minuses are - // replaced with underscores. - // - // As C++ identifiers are case-sensitive, we remember the "correct" - // spelling from the first occurrence of a rulename, all other - // occurrences are automatically changed to that. - // - // Certain rulenames are reserved as their equivalent C++ identifier is - // reserved as a keyword, an alternative token, by the standard or - // for other, special reasons. - // - // When using numerical values (num-val, repeat), the values - // must be in the range of the corresponding C++ data type. - // - // Remember we are defining a PEG, not a CFG. Simply copying some - // ABNF from somewhere might lead to surprising results as the - // alternations are now sequential, using the sor<> rule. + namespace grammar + { + // ABNF grammar according to RFC 5234, updated by RFC 7405, with + // the following differences: + // + // To form a C++ identifier from a rulename, all minuses are + // replaced with underscores. + // + // As C++ identifiers are case-sensitive, we remember the "correct" + // spelling from the first occurrence of a rulename, all other + // occurrences are automatically changed to that. + // + // Certain rulenames are reserved as their equivalent C++ identifier is + // reserved as a keyword, an alternative token, by the standard or + // for other, special reasons. + // + // When using numerical values (num-val, repeat), the values + // must be in the range of the corresponding C++ data type. + // + // Remember we are defining a PEG, not a CFG. Simply copying some + // ABNF from somewhere might lead to surprising results as the + // alternations are now sequential, using the sor<> rule. + // + // PEGs also require two extensions: The and-predicate and the + // not-predicate. They are expressed by '&' and '!' respectively, + // being allowed (optionally, only one of them) before the + // repetition. You can use braces for more complex expressions. + // + // Finally, instead of the pre-defined CRLF sequence, we accept + // any type of line ending as a convenience extension. + + // clang-format off + struct CRLF : sor< abnf::CRLF, CR, LF > {}; + + struct comment_cont : until< CRLF, sor< WSP, VCHAR > > {}; + struct comment : seq< one< ';' >, comment_cont > {}; + struct c_nl : sor< comment, CRLF > {}; + struct req_c_nl : c_nl {}; + struct c_wsp : sor< WSP, seq< c_nl, WSP > > {}; + + struct rulename : seq< ALPHA, star< ranges< 'a', 'z', 'A', 'Z', '0', '9', '-' > > > {}; + + struct quoted_string_cont : until< DQUOTE, print > {}; + struct quoted_string : seq< DQUOTE, quoted_string_cont > {}; + struct case_insensitive_string : seq< opt< istring< '%', 'i' > >, quoted_string > {}; + struct case_sensitive_string : seq< istring< '%', 's' >, quoted_string > {}; + struct char_val : sor< case_insensitive_string, case_sensitive_string > {}; + + struct prose_val_cont : until< one< '>' >, print > {}; + struct prose_val : seq< one< '<' >, prose_val_cont > {}; + + template< char First, typename Digit > + struct gen_val + { + struct value : plus< Digit > {}; + struct range : seq< one< '-' >, value > {}; + struct next_value : seq< value > {}; + struct type : seq< istring< First >, value, sor< range, star< one< '.' >, next_value > > > {}; + }; + + using hex_val = gen_val< 'x', HEXDIG >; + using dec_val = gen_val< 'd', DIGIT >; + using bin_val = gen_val< 'b', BIT >; + + struct num_val_choice : sor< bin_val::type, dec_val::type, hex_val::type > {}; + struct num_val : seq< one< '%' >, num_val_choice > {}; + + struct alternation; + struct option_close : one< ']' > {}; + struct option : seq< one< '[' >, pad< alternation, c_wsp >, option_close > {}; + struct group_close : one< ')' > {}; + struct group : seq< one< '(' >, pad< alternation, c_wsp >, group_close > {}; + struct element : sor< rulename, group, option, char_val, num_val, prose_val > {}; + + struct repeat : sor< seq< star< DIGIT >, one< '*' >, star< DIGIT > >, plus< DIGIT > > {}; + struct repetition : seq< opt< repeat >, element > {}; + struct req_repetition : seq< repetition > {}; + + struct and_predicate : seq< one< '&' >, req_repetition > {}; + struct not_predicate : seq< one< '!' >, req_repetition > {}; + struct predicate : sor< and_predicate, not_predicate, repetition > {}; + + struct concatenation : list< predicate, plus< c_wsp > > {}; + struct alternation : list< concatenation, pad< one< '/' >, c_wsp > > {}; + + struct defined_as_op : sor< string< '=', '/' >, one< '=' > > {}; + struct defined_as : pad< defined_as_op, c_wsp > {}; + struct rule : seq< seq< rulename, defined_as, alternation >, star< c_wsp >, req_c_nl > {}; + struct rulelist : until< eof, sor< seq< star< c_wsp >, c_nl >, rule > > {}; + // clang-format on + + } // namespace grammar + + // Using must_if<> we define a control class which is used for + // the parsing run instead of the default control class. // - // PEG also require two extensions: the and-predicate and the - // not-predicate. They are expressed by '&' and '!' respectively, - // being allowed (optionally, only one of them) before the - // repetition. You can use braces for more complex expressions. + // This improves the errors reported to the user. // - // Finally, instead of the pre-defined CRLF sequence, we accept - // any type of line ending as a convenience extension: + // The following turns local errors into global errors, i.e. + // if one of the rules for which a custom error message is + // defined fails, it throws a parse_error exception (aka global + // failure) instead of returning false (aka local failure). // clang-format off - struct CRLF : sor< abnf::CRLF, CR, LF > {}; + template< typename > inline constexpr const char* error_message = nullptr; - // The rest is according to the RFC(s): - struct comment_cont : until< CRLF, sor< WSP, VCHAR > > {}; - struct comment : if_must< one< ';' >, comment_cont > {}; - struct c_nl : sor< comment, CRLF > {}; - struct c_wsp : sor< WSP, seq< c_nl, WSP > > {}; + template<> inline constexpr auto error_message< abnf::grammar::comment_cont > = "unterminated comment"; - struct rulename : seq< ALPHA, star< ranges< 'a', 'z', 'A', 'Z', '0', '9', '-' > > > {}; - - struct quoted_string_cont : until< DQUOTE, print > {}; - struct quoted_string : if_must< DQUOTE, quoted_string_cont > {}; - struct case_insensitive_string : seq< opt< istring< '%', 'i' > >, quoted_string > {}; - struct case_sensitive_string : seq< istring< '%', 's' >, quoted_string > {}; - struct char_val : sor< case_insensitive_string, case_sensitive_string > {}; - - struct prose_val_cont : until< one< '>' >, print > {}; - struct prose_val : if_must< one< '<' >, prose_val_cont > {}; - - template< char First, typename Digit > - struct gen_val - { - struct value : plus< Digit > {}; - struct range : if_must< one< '-' >, value > {}; - struct next_value : must< value > {}; - struct type : seq< istring< First >, must< value >, sor< range, star< one< '.' >, next_value > > > {}; - }; + template<> inline constexpr auto error_message< abnf::grammar::quoted_string_cont > = "unterminated string (missing '\"')"; + template<> inline constexpr auto error_message< abnf::grammar::prose_val_cont > = "unterminated prose description (missing '>')"; - using hex_val = gen_val< 'x', HEXDIG >; - using dec_val = gen_val< 'd', DIGIT >; - using bin_val = gen_val< 'b', BIT >; + template<> inline constexpr auto error_message< abnf::grammar::hex_val::value > = "expected hexadecimal value"; + template<> inline constexpr auto error_message< abnf::grammar::dec_val::value > = "expected decimal value"; + template<> inline constexpr auto error_message< abnf::grammar::bin_val::value > = "expected binary value"; + template<> inline constexpr auto error_message< abnf::grammar::num_val_choice > = "expected base specifier (one of 'bBdDxX')"; - struct num_val_choice : sor< bin_val::type, dec_val::type, hex_val::type > {}; - struct num_val : if_must< one< '%' >, num_val_choice > {}; + template<> inline constexpr auto error_message< abnf::grammar::option_close > = "unterminated option (missing ']')"; + template<> inline constexpr auto error_message< abnf::grammar::group_close > = "unterminated group (missing ')')"; - struct alternation; - struct option_close : one< ']' > {}; - struct option : seq< one< '[' >, pad< must< alternation >, c_wsp >, must< option_close > > {}; - struct group_close : one< ')' > {}; - struct group : seq< one< '(' >, pad< must< alternation >, c_wsp >, must< group_close > > {}; - struct element : sor< rulename, group, option, char_val, num_val, prose_val > {}; + template<> inline constexpr auto error_message< abnf::grammar::req_repetition > = "expected element"; + template<> inline constexpr auto error_message< abnf::grammar::concatenation > = "expected element"; + template<> inline constexpr auto error_message< abnf::grammar::alternation > = "expected element"; - struct repeat : sor< seq< star< DIGIT >, one< '*' >, star< DIGIT > >, plus< DIGIT > > {}; - struct repetition : seq< opt< repeat >, element > {}; + template<> inline constexpr auto error_message< abnf::grammar::defined_as > = "expected '=' or '=/'"; + template<> inline constexpr auto error_message< abnf::grammar::req_c_nl > = "unterminated rule"; + template<> inline constexpr auto error_message< abnf::grammar::rule > = "expected rule"; - struct and_predicate : if_must< one< '&' >, repetition > {}; - struct not_predicate : if_must< one< '!' >, repetition > {}; - struct predicate : sor< and_predicate, not_predicate, repetition > {}; - - struct concatenation : list< predicate, plus< c_wsp > > {}; - struct alternation : list_must< concatenation, pad< one< '/' >, c_wsp > > {}; - - struct defined_as_op : sor< string< '=', '/' >, one< '=' > > {}; - struct defined_as : pad< defined_as_op, c_wsp > {}; - struct rule : seq< if_must< rulename, defined_as, alternation >, star< c_wsp >, must< c_nl > > {}; - struct rulelist : until< eof, sor< seq< star< c_wsp >, c_nl >, must< rule > > > {}; + struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; }; + template< typename Rule > using control = must_if< error >::control< Rule >; + // clang-format on - // end of grammar + // Since we are going to generate a parse tree, we define a + // selector that decides which rules will be included in our + // parse tree, which rules will be omitted from the parse tree, + // and which of the nodes will store the matched content. + // Additionally, some nodes will fold when they have exactly + // one child node. (see fold_one below) template< typename Rule > - struct error_control : normal< Rule > + struct selector + : parse_tree::selector< + Rule, + parse_tree::store_content::on< + grammar::rulename, + grammar::prose_val, + grammar::hex_val::value, + grammar::dec_val::value, + grammar::bin_val::value, + grammar::hex_val::range, + grammar::dec_val::range, + grammar::bin_val::range, + grammar::hex_val::type, + grammar::dec_val::type, + grammar::bin_val::type, + grammar::repeat, + grammar::defined_as_op >, + parse_tree::remove_content::on< + grammar::option, + grammar::and_predicate, + grammar::not_predicate, + grammar::rule >, + parse_tree::fold_one::on< + grammar::alternation, + grammar::group, + grammar::repetition, + grammar::concatenation > > + {}; + + // Besides the above "simple" list of selected rules, + // we also provide special handling to some nodes. + // When they are inserted into the parse tree, the + // transform method allows additional tree transformations + // in order to improve the generated tree. + + template<> + struct selector< grammar::quoted_string > + : std::true_type { - static const std::string error_message; - - template< typename Input, typename... States > - static void raise( const Input& in, States&&... /*unused*/ ) + template< typename... States > + static void transform( node_ptr& n ) { - throw parse_error( error_message, in ); + shift( n->m_begin, 1 ); + shift( n->m_end, -1 ); + + const auto content = n->string_view(); + for( const auto c : content ) { + if( std::isalpha( c ) != 0 ) { + n->set_type< istring_tag >(); + return; + } + } + if( content.size() == 1 ) { + n->set_type< one_tag >(); + } + else { + n->set_type< string_tag >(); + } } }; - template<> const std::string error_control< comment_cont >::error_message = "unterminated comment"; // NOLINT - - template<> const std::string error_control< quoted_string_cont >::error_message = "unterminated string (missing '\"')"; // NOLINT - template<> const std::string error_control< prose_val_cont >::error_message = "unterminated prose description (missing '>')"; // NOLINT - - template<> const std::string error_control< hex_val::value >::error_message = "expected hexadecimal value"; // NOLINT - template<> const std::string error_control< dec_val::value >::error_message = "expected decimal value"; // NOLINT - template<> const std::string error_control< bin_val::value >::error_message = "expected binary value"; // NOLINT - template<> const std::string error_control< num_val_choice >::error_message = "expected base specifier (one of 'bBdDxX')"; // NOLINT - - template<> const std::string error_control< option_close >::error_message = "unterminated option (missing ']')"; // NOLINT - template<> const std::string error_control< group_close >::error_message = "unterminated group (missing ')')"; // NOLINT - - template<> const std::string error_control< repetition >::error_message = "expected element"; // NOLINT - template<> const std::string error_control< concatenation >::error_message = "expected element"; // NOLINT - template<> const std::string error_control< alternation >::error_message = "expected element"; // NOLINT - - template<> const std::string error_control< defined_as >::error_message = "expected '=' or '=/'"; // NOLINT - template<> const std::string error_control< c_nl >::error_message = "unterminated rule"; // NOLINT - template<> const std::string error_control< rule >::error_message = "expected rule"; // NOLINT - // clang-format on - - } // namespace grammar - - template< typename Rule > - struct selector - : parse_tree::selector< - Rule, - parse_tree::store_content::on< - grammar::rulename, - grammar::prose_val, - grammar::hex_val::value, - grammar::dec_val::value, - grammar::bin_val::value, - grammar::hex_val::range, - grammar::dec_val::range, - grammar::bin_val::range, - grammar::hex_val::type, - grammar::dec_val::type, - grammar::bin_val::type, - grammar::repeat, - grammar::defined_as_op >, - parse_tree::remove_content::on< - grammar::option, - grammar::and_predicate, - grammar::not_predicate, - grammar::rule >, - parse_tree::fold_one::on< - grammar::alternation, - grammar::group, - grammar::repetition, - grammar::concatenation > > - { - }; - - template<> - struct selector< grammar::quoted_string > : std::true_type - { - template< typename... States > - static void transform( node_ptr& n ) + template<> + struct selector< grammar::case_sensitive_string > + : std::true_type { - shift( n->m_begin, 1 ); - shift( n->m_end, -1 ); - - const auto content = n->string_view(); - for( const auto c : content ) { - if( std::isalpha( c ) != 0 ) { - n->id = typeid( istring_tag ); - return; + template< typename... States > + static void transform( node_ptr& n ) + { + n = std::move( n->children.back() ); + if( n->string_view().size() == 1 ) { + n->set_type< one_tag >(); + } + else { + n->set_type< string_tag >(); } } - if( content.size() == 1 ) { - n->id = typeid( one_tag ); - } - else { - n->id = typeid( string_tag ); - } - } - }; - - template<> - struct selector< grammar::case_sensitive_string > : std::true_type - { - template< typename... States > - static void transform( node_ptr& n ) - { - n = std::move( n->children.back() ); - if( n->string_view().size() == 1 ) { - n->id = typeid( one_tag ); - } - else { - n->id = typeid( string_tag ); - } - } - }; + }; - std::string to_string( const node_ptr& n ); - std::string to_string( const std::vector< node_ptr >& v ); + std::string to_string( const node_ptr& n ); + std::string to_string( const std::vector< node_ptr >& v ); - std::string to_string_unwrap_seq( const node_ptr& n ) - { - if( n->is< grammar::group >() || n->is< grammar::concatenation >() ) { - return to_string( n->children ); - } - return to_string( n ); - } - - namespace - { - std::string get_rulename( const node_ptr& n ) + std::string to_string_unwrap_seq( const node_ptr& n ) { - assert( n->is< grammar::rulename >() ); - std::string v = n->string(); - std::replace( v.begin(), v.end(), '-', '_' ); - return v; + if( n->is_type< grammar::group >() || n->is_type< grammar::concatenation >() ) { + return to_string( n->children ); + } + return to_string( n ); } - std::string get_rulename( const node_ptr& n, const bool print_forward_declarations ) + namespace { - std::string v = get_rulename( n ); - const auto it = find_rule( rules, v ); - if( it != rules.rend() ) { - return *it; - } - if( keywords.count( v ) != 0 || v.find( "__" ) != std::string::npos ) { - throw parse_error( '\'' + n->string() + "' is a reserved rulename", n->begin() ); // NOLINT - } - if( print_forward_declarations && find_rule( rules_defined, v ) != rules_defined.rend() ) { - std::cout << "struct " << v << ";\n"; + std::string get_rulename( const node_ptr& n ) + { + assert( n->is_type< grammar::rulename >() ); + std::string v = n->string(); + std::replace( v.begin(), v.end(), '-', '_' ); + return v; } - rules.push_back( v ); - return v; - } - template< typename T > - std::string gen_val( const node_ptr& n ) - { - if( n->children.size() == 2 ) { - if( n->children.back()->is< T >() ) { - return prefix + "range< " + to_string( n->children.front() ) + ", " + to_string( n->children.back()->children.front() ) + " >"; + std::string get_rulename( const node_ptr& n, const bool print_forward_declarations ) + { + std::string v = get_rulename( n ); + const auto it = find_rule( rules, v ); + if( it != rules.rend() ) { + return *it; } + if( keywords.count( v ) != 0 || v.find( "__" ) != std::string::npos ) { + throw parse_error( '\'' + n->string() + "' is a reserved rulename", n->begin() ); + } + if( print_forward_declarations && find_rule( rules_defined, v ) != rules_defined.rend() ) { + std::cout << "struct " << v << ";\n"; + } + rules.push_back( v ); + return v; } - if( n->children.size() == 1 ) { - return prefix + "one< " + to_string( n->children ) + " >"; - } - return prefix + "string< " + to_string( n->children ) + " >"; - } - struct ccmp - { - bool operator()( const std::string& lhs, const std::string& rhs ) const noexcept + template< typename T > + std::string gen_val( const node_ptr& n ) { - return TAO_PEGTL_STRCASECMP( lhs.c_str(), rhs.c_str() ) < 0; + if( n->children.size() == 2 ) { + if( n->children.back()->is_type< T >() ) { + return prefix + "range< " + to_string( n->children.front() ) + ", " + to_string( n->children.back()->children.front() ) + " >"; + } + } + if( n->children.size() == 1 ) { + return prefix + "one< " + to_string( n->children ) + " >"; + } + return prefix + "string< " + to_string( n->children ) + " >"; } - }; - std::map< std::string, parse_tree::node*, ccmp > previous_rules; // NOLINT + struct ccmp + { + bool operator()( const std::string& lhs, const std::string& rhs ) const noexcept + { + return TAO_PEGTL_STRCASECMP( lhs.c_str(), rhs.c_str() ) < 0; + } + }; + + std::map< std::string, parse_tree::node*, ccmp > previous_rules; - } // namespace + } // namespace - template<> - struct selector< grammar::rule > : std::true_type - { - template< typename... States > - static void transform( node_ptr& n ) + template<> + struct selector< grammar::rule > + : std::true_type { - const auto rname = get_rulename( n->children.front() ); - assert( n->children.at( 1 )->is< grammar::defined_as_op >() ); - const auto op = n->children.at( 1 )->string(); - // when we insert a normal rule, we need to check for duplicates - if( op == "=" ) { - if( !previous_rules.insert( { rname, n.get() } ).second ) { - throw parse_error( "rule '" + rname + "' is already defined", n->begin() ); // NOLINT - } - } - // if it is an "incremental alternation", we need to consolidate the assigned alternations - else if( op == "=/" ) { - const auto p = previous_rules.find( rname ); - if( p == previous_rules.end() ) { - throw parse_error( "incremental alternation '" + rname + "' without previous rule definition", n->begin() ); // NOLINT - } - auto& previous = p->second->children.back(); - - // if the previous rule does not assign an alternation, create an intermediate alternation and move its assignee into it. - if( !previous->is< abnf::grammar::alternation >() ) { - auto s = std::make_unique< parse_tree::node >(); - s->id = typeid( abnf::grammar::alternation ); - s->source = previous->source; - s->m_begin = previous->m_begin; - s->m_end = previous->m_end; - s->children.emplace_back( std::move( previous ) ); - previous = std::move( s ); + template< typename... States > + static void transform( node_ptr& n ) + { + const auto rname = get_rulename( n->children.front() ); + assert( n->children.at( 1 )->is_type< grammar::defined_as_op >() ); + const auto op = n->children.at( 1 )->string(); + // when we insert a normal rule, we need to check for duplicates + if( op == "=" ) { + if( !previous_rules.try_emplace( rname, n.get() ).second ) { + throw parse_error( "rule '" + rname + "' is already defined", n->begin() ); + } } + // if it is an "incremental alternation", we need to consolidate the assigned alternations + else if( op == "=/" ) { + const auto p = previous_rules.find( rname ); + if( p == previous_rules.end() ) { + throw parse_error( "incremental alternation '" + rname + "' without previous rule definition", n->begin() ); + } + auto& previous = p->second->children.back(); + + // if the previous rule does not assign an alternation, create an intermediate alternation and move its assignee into it. + if( !previous->is_type< abnf::grammar::alternation >() ) { + auto s = std::make_unique< parse_tree::node >(); + s->set_type< abnf::grammar::alternation >(); + s->source = previous->source; + s->m_begin = previous->m_begin; + s->m_end = previous->m_end; + s->children.emplace_back( std::move( previous ) ); + previous = std::move( s ); + } - // append all new options to the previous rule's assignee (which always is an alternation now) - previous->m_end = n->children.back()->m_end; + // append all new options to the previous rule's assignee (which always is an alternation now) + previous->m_end = n->children.back()->m_end; - // if the new rule itself contains an alternation, append the individual entries... - if( n->children.back()->is< abnf::grammar::alternation >() ) { - for( auto& e : n->children.back()->children ) { - previous->children.emplace_back( std::move( e ) ); + // if the new rule itself contains an alternation, append the individual entries... + if( n->children.back()->is_type< abnf::grammar::alternation >() ) { + for( auto& e : n->children.back()->children ) { + previous->children.emplace_back( std::move( e ) ); + } } + // ...otherwise add the node itself as another option. + else { + previous->children.emplace_back( std::move( n->children.back() ) ); + } + n.reset(); } - // ...otherwise add the node itself as another option. else { - previous->children.emplace_back( std::move( n->children.back() ) ); + throw parse_error( "invalid operator '" + op + "', this should not happen!", n->begin() ); } - n.reset(); - } - else { - throw parse_error( "invalid operator '" + op + "', this should not happen!", n->begin() ); // NOLINT } - } - }; - - struct stringifier - { - using function_t = std::string ( * )( const node_ptr& n ); - function_t default_ = nullptr; + }; - std::map< std::type_index, function_t > map_; + // Finally, the generated parse tree for each node is converted to + // a C++ source code string. - template< typename T > - void add( const function_t& f ) + struct stringifier { - map_.insert( { typeid( T ), f } ); - } + using function_t = std::string ( * )( const node_ptr& n ); + function_t default_ = nullptr; - std::string operator()( const node_ptr& n ) const - { - const auto it = map_.find( n->id ); - if( it != map_.end() ) { - return it->second( n ); + std::map< std::string_view, function_t > map_; + + template< typename T > + void add( const function_t& f ) + { + map_.try_emplace( internal::demangle< T >(), f ); } - return default_( n ); - } - }; - stringifier make_stringifier() - { - stringifier nrv; - nrv.default_ = []( const node_ptr& n ) -> std::string { - throw parse_error( "missing to_string() for " + n->name(), n->begin() ); // NOLINT + std::string operator()( const node_ptr& n ) const + { + const auto it = map_.find( n->type ); + if( it != map_.end() ) { + return it->second( n ); + } + return default_( n ); + } }; - nrv.add< grammar::rulename >( []( const node_ptr& n ) { return get_rulename( n, true ); } ); - - nrv.add< grammar::rule >( []( const node_ptr& n ) { - return "struct " + get_rulename( n->children.front(), false ) + " : " + to_string( n->children.back() ) + " {};"; - } ); - - nrv.add< string_tag >( []( const node_ptr& n ) { - const auto content = n->string_view(); - std::string s; - for( const auto c : content ) { - append_char( s, c ); - } - return prefix + "string< " + s + " >"; - } ); - - nrv.add< istring_tag >( []( const node_ptr& n ) { - const auto content = n->string_view(); - std::string s; - for( const auto c : content ) { - append_char( s, c ); - } - return prefix + "istring< " + s + " >"; - } ); - - nrv.add< one_tag >( []( const node_ptr& n ) { - const auto content = n->string_view(); - std::string s; - for( const auto c : content ) { - append_char( s, c ); - } - return prefix + "one< " + s + " >"; - } ); - - nrv.add< grammar::hex_val::value >( []( const node_ptr& n ) { return "0x" + n->string(); } ); - nrv.add< grammar::dec_val::value >( []( const node_ptr& n ) { return n->string(); } ); - nrv.add< grammar::bin_val::value >( []( const node_ptr& n ) { - unsigned long long v = 0; - const char* p = n->m_begin.data; - // TODO: Detect overflow - do { - v <<= 1; - v |= ( *p++ & 1 ); - } while( p != n->m_end.data ); - std::ostringstream o; - o << v; - return o.str(); - } ); - - nrv.add< grammar::hex_val::type >( []( const node_ptr& n ) { return gen_val< grammar::hex_val::range >( n ); } ); - nrv.add< grammar::dec_val::type >( []( const node_ptr& n ) { return gen_val< grammar::dec_val::range >( n ); } ); - nrv.add< grammar::bin_val::type >( []( const node_ptr& n ) { return gen_val< grammar::bin_val::range >( n ); } ); - - nrv.add< grammar::alternation >( []( const node_ptr& n ) { return prefix + "sor< " + to_string( n->children ) + " >"; } ); - nrv.add< grammar::option >( []( const node_ptr& n ) { return prefix + "opt< " + to_string( n->children ) + " >"; } ); - nrv.add< grammar::group >( []( const node_ptr& n ) { return prefix + "seq< " + to_string( n->children ) + " >"; } ); - - nrv.add< grammar::prose_val >( []( const node_ptr& n ) { return "/* " + n->string() + " */"; } ); - - nrv.add< grammar::and_predicate >( []( const node_ptr& n ) { - assert( n->children.size() == 1 ); - return prefix + "at< " + to_string_unwrap_seq( n->children.front() ) + " >"; - } ); - - nrv.add< grammar::not_predicate >( []( const node_ptr& n ) { - assert( n->children.size() == 1 ); - return prefix + "not_at< " + to_string_unwrap_seq( n->children.front() ) + " >"; - } ); - - nrv.add< grammar::concatenation >( []( const node_ptr& n ) { - assert( !n->children.empty() ); - return prefix + "seq< " + to_string( n->children ) + " >"; - } ); - - nrv.add< grammar::repetition >( []( const node_ptr& n ) -> std::string { - assert( n->children.size() == 2 ); - const auto content = to_string_unwrap_seq( n->children.back() ); - const auto rep = n->children.front()->string(); - const auto star = rep.find( '*' ); - if( star == std::string::npos ) { - const auto v = remove_leading_zeroes( rep ); - if( v.empty() ) { - throw parse_error( "repetition of zero not allowed", n->begin() ); // NOLINT + stringifier make_stringifier() + { + stringifier nrv; + nrv.default_ = []( const node_ptr& n ) -> std::string { + throw parse_error( "missing to_string() for " + std::string( n->type ), n->begin() ); + }; + + nrv.add< grammar::rulename >( []( const node_ptr& n ) { return get_rulename( n, true ); } ); + + nrv.add< grammar::rule >( []( const node_ptr& n ) { + return "struct " + get_rulename( n->children.front(), false ) + " : " + to_string( n->children.back() ) + " {};"; + } ); + + nrv.add< string_tag >( []( const node_ptr& n ) { + const auto content = n->string_view(); + std::string s; + for( const auto c : content ) { + append_char( s, c ); } - return prefix + "rep< " + v + ", " + content + " >"; - } - const auto min = remove_leading_zeroes( rep.substr( 0, star ) ); - const auto max = remove_leading_zeroes( rep.substr( star + 1 ) ); - if( ( star != rep.size() - 1 ) && max.empty() ) { - throw parse_error( "repetition maximum of zero not allowed", n->begin() ); // NOLINT - } - if( min.empty() && max.empty() ) { - return prefix + "star< " + content + " >"; - } - if( !min.empty() && max.empty() ) { - if( min == "1" ) { - return prefix + "plus< " + content + " >"; + return prefix + "string< " + s + " >"; + } ); + + nrv.add< istring_tag >( []( const node_ptr& n ) { + const auto content = n->string_view(); + std::string s; + for( const auto c : content ) { + append_char( s, c ); } - return prefix + "rep_min< " + min + ", " + content + " >"; - } - if( min.empty() && !max.empty() ) { - if( max == "1" ) { - return prefix + "opt< " + content + " >"; + return prefix + "istring< " + s + " >"; + } ); + + nrv.add< one_tag >( []( const node_ptr& n ) { + const auto content = n->string_view(); + std::string s; + for( const auto c : content ) { + append_char( s, c ); } - return prefix + "rep_max< " + max + ", " + content + " >"; - } - unsigned long long min_val; - unsigned long long max_val; - { - std::stringstream s; - s.str( min ); - s >> min_val; - s.clear(); - s.str( max ); - s >> max_val; - } - if( min_val > max_val ) { - throw parse_error( "repetition minimum which is greater than the repetition maximum not allowed", n->begin() ); // NOLINT - } - if( ( min_val == 1 ) && ( max_val == 1 ) ) { - // note: content can not be used here! - return to_string( n->children.back() ); - } - const auto min_element = ( min_val == 1 ) ? content : ( prefix + "rep< " + min + ", " + content + " >" ); - if( min_val == max_val ) { - return min_element; - } - std::ostringstream os; - os << ( max_val - min_val ); - const auto max_element = prefix + ( ( max_val - min_val == 1 ) ? "opt< " : ( "rep_opt< " + os.str() + ", " ) ) + content + " >"; - return prefix + "seq< " + min_element + ", " + max_element + " >"; - } ); + return prefix + "one< " + s + " >"; + } ); + + nrv.add< grammar::hex_val::value >( []( const node_ptr& n ) { return "0x" + n->string(); } ); + nrv.add< grammar::dec_val::value >( []( const node_ptr& n ) { return n->string(); } ); + nrv.add< grammar::bin_val::value >( []( const node_ptr& n ) { + unsigned long long v = 0; + const char* p = n->m_begin.data; + // TODO: Detect overflow + do { + v <<= 1; + v |= ( *p++ & 1 ); + } while( p != n->m_end.data ); + std::ostringstream o; + o << v; + return o.str(); + } ); + + nrv.add< grammar::hex_val::type >( []( const node_ptr& n ) { return gen_val< grammar::hex_val::range >( n ); } ); + nrv.add< grammar::dec_val::type >( []( const node_ptr& n ) { return gen_val< grammar::dec_val::range >( n ); } ); + nrv.add< grammar::bin_val::type >( []( const node_ptr& n ) { return gen_val< grammar::bin_val::range >( n ); } ); + + nrv.add< grammar::alternation >( []( const node_ptr& n ) { return prefix + "sor< " + to_string( n->children ) + " >"; } ); + nrv.add< grammar::option >( []( const node_ptr& n ) { return prefix + "opt< " + to_string( n->children ) + " >"; } ); + nrv.add< grammar::group >( []( const node_ptr& n ) { return prefix + "seq< " + to_string( n->children ) + " >"; } ); + + nrv.add< grammar::prose_val >( []( const node_ptr& n ) { return "/* " + n->string() + " */"; } ); + + nrv.add< grammar::and_predicate >( []( const node_ptr& n ) { + assert( n->children.size() == 1 ); + return prefix + "at< " + to_string_unwrap_seq( n->children.front() ) + " >"; + } ); + + nrv.add< grammar::not_predicate >( []( const node_ptr& n ) { + assert( n->children.size() == 1 ); + return prefix + "not_at< " + to_string_unwrap_seq( n->children.front() ) + " >"; + } ); + + nrv.add< grammar::concatenation >( []( const node_ptr& n ) { + assert( !n->children.empty() ); + return prefix + "seq< " + to_string( n->children ) + " >"; + } ); + + nrv.add< grammar::repetition >( []( const node_ptr& n ) -> std::string { + assert( n->children.size() == 2 ); + const auto content = to_string_unwrap_seq( n->children.back() ); + const auto rep = n->children.front()->string(); + const auto star = rep.find( '*' ); + if( star == std::string::npos ) { + const auto v = remove_leading_zeroes( rep ); + if( v.empty() ) { + throw parse_error( "repetition of zero not allowed", n->begin() ); + } + return prefix + "rep< " + v + ", " + content + " >"; + } + const auto min = remove_leading_zeroes( rep.substr( 0, star ) ); + const auto max = remove_leading_zeroes( rep.substr( star + 1 ) ); + if( ( star != rep.size() - 1 ) && max.empty() ) { + throw parse_error( "repetition maximum of zero not allowed", n->begin() ); + } + if( min.empty() && max.empty() ) { + return prefix + "star< " + content + " >"; + } + if( !min.empty() && max.empty() ) { + if( min == "1" ) { + return prefix + "plus< " + content + " >"; + } + return prefix + "rep_min< " + min + ", " + content + " >"; + } + if( min.empty() && !max.empty() ) { + if( max == "1" ) { + return prefix + "opt< " + content + " >"; + } + return prefix + "rep_max< " + max + ", " + content + " >"; + } + unsigned long long min_val; + unsigned long long max_val; + { + std::stringstream s; + s.str( min ); + s >> min_val; + s.clear(); + s.str( max ); + s >> max_val; + } + if( min_val > max_val ) { + throw parse_error( "repetition minimum which is greater than the repetition maximum not allowed", n->begin() ); + } + if( ( min_val == 1 ) && ( max_val == 1 ) ) { + // note: content can not be used here! + return to_string( n->children.back() ); + } + auto min_element = ( min_val == 1 ) ? content : ( prefix + "rep< " + min + ", " + content + " >" ); + if( min_val == max_val ) { + return min_element; + } + std::ostringstream os; + os << ( max_val - min_val ); + const auto max_element = prefix + ( ( max_val - min_val == 1 ) ? "opt< " : ( "rep_opt< " + os.str() + ", " ) ) + content + " >"; + return prefix + "seq< " + min_element + ", " + max_element + " >"; + } ); - return nrv; - } + return nrv; + } - std::string to_string( const node_ptr& n ) - { - static stringifier s = make_stringifier(); - return s( n ); - } + std::string to_string( const node_ptr& n ) + { + static stringifier s = make_stringifier(); + return s( n ); + } - std::string to_string( const std::vector< node_ptr >& v ) - { - std::string result; - for( const auto& c : v ) { - if( !result.empty() ) { - result += ", "; + std::string to_string( const std::vector< node_ptr >& v ) + { + std::string result; + for( const auto& c : v ) { + if( !result.empty() ) { + result += ", "; + } + result += to_string( c ); } - result += to_string( c ); + return result; } - return result; - } -} // namespace TAO_PEGTL_NAMESPACE::abnf + } // namespace abnf + +} // namespace TAO_PEGTL_NAMESPACE -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { - using namespace TAO_PEGTL_NAMESPACE; // NOLINT + using namespace TAO_PEGTL_NAMESPACE; if( argc != 2 ) { std::cerr << "Usage: " << argv[ 0 ] << " SOURCE" << std::endl; @@ -693,7 +727,7 @@ int main( int argc, char** argv ) file_input in( argv[ 1 ] ); try { - const auto root = parse_tree::parse< abnf::grammar::rulelist, abnf::selector, nothing, abnf::grammar::error_control >( in ); + const auto root = parse_tree::parse< abnf::grammar::rulelist, abnf::selector, nothing, abnf::control >( in ); for( const auto& rule : root->children ) { abnf::rules_defined.push_back( abnf::get_rulename( rule->children.front() ) ); diff --git a/packages/PEGTL/src/example/pegtl/analyze.cpp b/packages/PEGTL/src/example/pegtl/analyze.cpp index ecccbef9bd33e1f06b70b0de0e8a5bd4930e921f..1079686f185282854f767525c7ee295ec797ac9d 100644 --- a/packages/PEGTL/src/example/pegtl/analyze.cpp +++ b/packages/PEGTL/src/example/pegtl/analyze.cpp @@ -1,24 +1,23 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <tao/pegtl.hpp> -#include <tao/pegtl/analyze.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +#include <tao/pegtl/contrib/analyze.hpp> + +using namespace TAO_PEGTL_NAMESPACE; struct bar; struct foo : sor< digit, bar > -{ -}; +{}; struct bar : plus< foo > -{ -}; +{}; -int main( int /*unused*/, char** /*unused*/ ) +int main() // NOLINT(bugprone-exception-escape) { if( analyze< foo >() != 0 ) { std::cout << "there are problems" << std::endl; diff --git a/packages/PEGTL/src/example/pegtl/calculator.cpp b/packages/PEGTL/src/example/pegtl/calculator.cpp index b841e327a3ee5b317f93e2611069588b6a6e337e..4612216f58fe47efd7d85273f141ea1202217fce 100644 --- a/packages/PEGTL/src/example/pegtl/calculator.cpp +++ b/packages/PEGTL/src/example/pegtl/calculator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cassert> @@ -13,7 +13,7 @@ // Include the analyze function that checks // a grammar for possible infinite cycles. -#include <tao/pegtl/analyze.hpp> +#include <tao/pegtl/contrib/analyze.hpp> namespace pegtl = TAO_PEGTL_NAMESPACE; @@ -168,7 +168,7 @@ namespace calculator void insert( const std::string& name, const order p, const std::function< long( long, long ) >& f ) { assert( !name.empty() ); - m_ops.emplace( name, op{ p, f } ); + m_ops.try_emplace( name, op{ p, f } ); } [[nodiscard]] const std::map< std::string, op >& ops() const noexcept @@ -182,7 +182,7 @@ namespace calculator // Here the actual grammar starts. - using namespace tao::pegtl; // NOLINT + using namespace tao::pegtl; // Comments are introduced by a '#' and proceed to the end-of-line/file. @@ -205,7 +205,7 @@ namespace calculator struct infix { - using analyze_t = analysis::generic< analysis::rule_type::any >; + using rule_t = ascii::any::rule_t; template< apply_mode, rewind_mode, @@ -213,9 +213,9 @@ namespace calculator class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& in, const operators& b, stacks& s, States&&... /*unused*/ ) + static bool match( ParseInput& in, const operators& b, stacks& s, States&&... /*unused*/ ) { // Look for the longest match of the input against the operators in the operator map. @@ -223,8 +223,8 @@ namespace calculator } private: - template< typename Input > - static bool match( Input& in, const operators& b, stacks& s, std::string t ) + template< typename ParseInput > + static bool match( ParseInput& in, const operators& b, stacks& s, std::string t ) { if( in.size( t.size() + 1 ) > t.size() ) { t += in.peek_char( t.size() ); @@ -299,8 +299,8 @@ namespace calculator template<> struct action< number > { - template< typename Input > - static void apply( const Input& in, const operators& /*unused*/, stacks& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, const operators& /*unused*/, stacks& s ) { std::stringstream ss( in.string() ); long v; @@ -332,7 +332,7 @@ namespace calculator } // namespace calculator -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { // Check the grammar for some possible issues. diff --git a/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp b/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp index cfda7474729ab13176b68bde15539919c9301d3b..7624b26f79ec132ebaffecb82210433146e60c3f 100644 --- a/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp +++ b/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cassert> @@ -20,8 +20,7 @@ namespace example struct type_3 : pegtl::star< pegtl::one< 'a' >, pegtl::plus< pegtl::one< 'b' > > > - { - }; + {}; // Type 2 - Context Free Languages @@ -31,8 +30,7 @@ namespace example struct type_2_recursive : pegtl::sor< pegtl::string< 'a', 'b' >, pegtl::seq< pegtl::one< 'a' >, type_2_recursive, pegtl::one< 'b' > > > - { - }; + {}; // Implementation that uses state instead of recursion, an // action to set the state, and a custom rule to use it. @@ -46,9 +44,9 @@ namespace example class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& in, std::size_t& count, States&&... /*unused*/ ) + static bool match( ParseInput& in, std::size_t& count, States&&... /*unused*/ ) { if( in.size( count ) >= count ) { for( std::size_t i = 0; i < count; ++i ) { @@ -65,19 +63,17 @@ namespace example struct type_2_with_state : pegtl::seq< pegtl::star< pegtl::one< 'a' > >, match_n< 'b' > > - { - }; + {}; template< typename Rule > struct action_2_with_state - { - }; + {}; template<> struct action_2_with_state< pegtl::star< pegtl::one< 'a' > > > { - template< typename Input > - static void apply( const Input& in, std::size_t& count ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::size_t& count ) { count = in.size(); } @@ -93,14 +89,12 @@ namespace example struct type_1 : pegtl::seq< pegtl::star< pegtl::one< 'a' > >, match_n< 'b' >, match_n< 'c' > > - { - }; + {}; template< typename Rule > struct action_1 : action_2_with_state< Rule > - { - }; + {}; // Type 0 - Recursively Enumerable Languages diff --git a/packages/PEGTL/src/example/pegtl/csv1.cpp b/packages/PEGTL/src/example/pegtl/csv1.cpp index f17c73936b955a099fdf17eb11e4a80d0aefc66d..b81eb638e402c52302e95a75919d40b0b37c70c4 100644 --- a/packages/PEGTL/src/example/pegtl/csv1.cpp +++ b/packages/PEGTL/src/example/pegtl/csv1.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cassert> @@ -50,8 +50,8 @@ namespace csv1 template<> struct action< value > { - template< typename Input > - static void apply( const Input& in, result_data& data ) + template< typename ActionInput > + static void apply( const ActionInput& in, result_data& data ) { assert( !data.empty() ); std::stringstream ss( in.string() ); @@ -64,21 +64,20 @@ namespace csv1 template< typename Rule > struct control : pegtl::normal< Rule > - { - }; + {}; template<> struct control< value_line > : pegtl::normal< value_line > { - template< typename Input > - static void start( Input& /*unused*/, result_data& data ) + template< typename ParseInput > + static void start( ParseInput& /*unused*/, result_data& data ) { data.emplace_back(); } - template< typename Input > - static void failure( Input& /*unused*/, result_data& data ) + template< typename ParseInput > + static void failure( ParseInput& /*unused*/, result_data& data ) { assert( !data.empty() ); data.pop_back(); @@ -87,7 +86,7 @@ namespace csv1 } // namespace csv1 -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { for( int i = 1; i < argc; ++i ) { pegtl::file_input in( argv[ i ] ); diff --git a/packages/PEGTL/src/example/pegtl/csv2.cpp b/packages/PEGTL/src/example/pegtl/csv2.cpp index dcc2a06a2f4e468b5c19f18acbff92c17300c3f8..328744a0e9896590ac17ac14bd004d639f7fffef 100644 --- a/packages/PEGTL/src/example/pegtl/csv2.cpp +++ b/packages/PEGTL/src/example/pegtl/csv2.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <iostream> @@ -23,7 +23,7 @@ namespace csv2 // aha """,yes, this works // clang-format off - template< int C > struct string_without : pegtl::star< pegtl::not_one< C, 10, 13 > > {}; + template< char C > struct string_without : pegtl::star< pegtl::not_one< C, 10, 13 > > {}; struct plain_value : string_without< ',' > {}; struct quoted_value : pegtl::if_must< pegtl::one< '"' >, string_without< '"' >, pegtl::one< '"' > > {}; struct value : pegtl::sor< quoted_value, plain_value > {}; @@ -91,8 +91,8 @@ namespace csv2 template<> struct action< plain_value > { - template< typename Input, unsigned N > - static void apply( const Input& in, result_data< N >& data ) + template< typename ActionInput, unsigned N > + static void apply( const ActionInput& in, result_data< N >& data ) { data.temp.push_back( in.string() ); } @@ -108,8 +108,8 @@ namespace csv2 { using tuple_t = typename tuple_help< N, std::tuple<> >::tuple_t; - template< typename Input > - static void apply( const Input& in, result_data< N >& data ) + template< typename ActionInput > + static void apply( const ActionInput& in, result_data< N >& data ) { if( data.temp.size() != N ) { throw pegtl::parse_error( "column count mismatch", in ); @@ -168,7 +168,7 @@ namespace csv2 } // namespace csv2 -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { for( int i = 1; i < argc; ++i ) { pegtl::file_input in( argv[ i ] ); diff --git a/packages/PEGTL/src/example/pegtl/double.hpp b/packages/PEGTL/src/example/pegtl/double.hpp index 02eb259440154077888dab1de60ed7bf5b6360b5..c7eedd4dccaea30f45bf819ed31f7117b798622d 100644 --- a/packages/PEGTL/src/example/pegtl/double.hpp +++ b/packages/PEGTL/src/example/pegtl/double.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_DOUBLE_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_DOUBLE_HPP #define TAO_PEGTL_SRC_EXAMPLES_PEGTL_DOUBLE_HPP #include <tao/pegtl.hpp> @@ -11,7 +11,7 @@ namespace double_ // A grammar for doubles suitable for std::stod without locale support. // See also: http://en.cppreference.com/w/cpp/string/basic_string/stof - using namespace TAO_PEGTL_NAMESPACE; // NOLINT + using namespace TAO_PEGTL_NAMESPACE; // clang-format off struct plus_minus : opt< one< '+', '-' > > {}; diff --git a/packages/PEGTL/src/example/pegtl/dynamic_match.cpp b/packages/PEGTL/src/example/pegtl/dynamic_match.cpp index 55495006bd4598093b4986b8d59f549fb43964d4..da9f2dc24623dc5ce150b1847d1347c994aecc1f 100644 --- a/packages/PEGTL/src/example/pegtl/dynamic_match.cpp +++ b/packages/PEGTL/src/example/pegtl/dynamic_match.cpp @@ -1,6 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ +#include <cassert> #include <cstring> #include <iostream> @@ -8,6 +9,8 @@ #include <tao/pegtl.hpp> +#include <tao/pegtl/contrib/analyze.hpp> + namespace pegtl = TAO_PEGTL_NAMESPACE; namespace dynamic @@ -22,15 +25,17 @@ namespace dynamic struct long_literal_mark { + using rule_t = long_literal_mark; + template< pegtl::apply_mode, pegtl::rewind_mode, template< typename... > class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& in, const std::string& id, const std::string& /*unused*/, States&&... /*unused*/ ) + static bool match( ParseInput& in, const std::string& id, const std::string& /*unused*/, States&&... /*unused*/ ) { if( in.size( id.size() ) >= id.size() ) { if( std::memcmp( in.current(), id.data(), id.size() ) == 0 ) { @@ -61,8 +66,8 @@ namespace dynamic template<> struct action< long_literal_id > { - template< typename Input > - static void apply( const Input& in, std::string& id, const std::string& /*unused*/ ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& id, const std::string& /*unused*/ ) { id = in.string(); } @@ -71,8 +76,8 @@ namespace dynamic template<> struct action< long_literal_body > { - template< typename Input > - static void apply( const Input& in, const std::string& /*unused*/, std::string& body ) + template< typename ActionInput > + static void apply( const ActionInput& in, const std::string& /*unused*/, std::string& body ) { body += in.string(); } @@ -80,8 +85,20 @@ namespace dynamic } // namespace dynamic -int main( int argc, char** argv ) +namespace TAO_PEGTL_NAMESPACE { + template< typename Name > + struct analyze_traits< Name, dynamic::long_literal_mark > + : analyze_any_traits<> + {}; + +} // namespace TAO_PEGTL_NAMESPACE + +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) +{ + const auto issues = pegtl::analyze< dynamic::grammar >(); + assert( !issues ); + if( argc > 1 ) { std::string id; std::string body; diff --git a/packages/PEGTL/src/example/pegtl/hello_world.cpp b/packages/PEGTL/src/example/pegtl/hello_world.cpp index 18a6ae2b3b6fb977cba8926e13d433e4e01c2d73..4ff0cd258e0358cedf28edacf4d4a388f39ce624 100644 --- a/packages/PEGTL/src/example/pegtl/hello_world.cpp +++ b/packages/PEGTL/src/example/pegtl/hello_world.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <iostream> @@ -23,8 +23,8 @@ namespace hello template<> struct action< name > { - template< typename Input > - static void apply( const Input& in, std::string& v ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& v ) { v = in.string(); } @@ -32,7 +32,7 @@ namespace hello } // namespace hello -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { if( argc > 1 ) { std::string name; diff --git a/packages/PEGTL/src/example/pegtl/indent_aware.cpp b/packages/PEGTL/src/example/pegtl/indent_aware.cpp index 1d504a82a54333402746acf422dfd74ebb99b98e..27b484aac59b77077e23cd83c9bb6bec136b41b9 100644 --- a/packages/PEGTL/src/example/pegtl/indent_aware.cpp +++ b/packages/PEGTL/src/example/pegtl/indent_aware.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cassert> @@ -132,12 +132,12 @@ namespace example template<> struct action< else_line > { - template< typename Input > - static void apply( const Input& in, state& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, state& s ) { assert( !s.stack.empty() ); if( ( s.stack.back().type != type::if_ ) || ( s.stack.back().indent != s.current_indent ) ) { - throw pegtl::parse_error( "expected previous 'if' on same indent as current 'else'", in ); // NOLINT + throw pegtl::parse_error( "expected previous 'if' on same indent as current 'else'", in ); } s.stack.back().type = type::else_; } @@ -155,11 +155,11 @@ namespace example template<> struct action< nothing > { - template< typename Input > - static void apply( const Input& in, state& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, state& s ) { if( s.minimum_indent > 0 ) { - throw pegtl::parse_error( "expected indented block instead of empty line", in ); // NOLINT + throw pegtl::parse_error( "expected indented block instead of empty line", in ); } s.stack.clear(); } @@ -168,8 +168,8 @@ namespace example template<> struct action< indent > { - template< typename Input > - static void apply( const Input& in, state& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, state& s ) { s.current_indent = in.size(); if( s.current_indent != 0 ) { @@ -179,12 +179,12 @@ namespace example } if( s.minimum_indent > 0 ) { if( s.current_indent < s.minimum_indent ) { - throw pegtl::parse_error( "expected indented block with more indent", in ); // NOLINT + throw pegtl::parse_error( "expected indented block with more indent", in ); } s.minimum_indent = 0; } else if( ( !s.stack.empty() ) && ( s.current_indent != s.stack.back().indent ) ) { - throw pegtl::parse_error( "indentation mismatch", in ); // NOLINT + throw pegtl::parse_error( "indentation mismatch", in ); } } }; @@ -192,18 +192,18 @@ namespace example template<> struct action< grammar > { - template< typename Input > - static void apply( const Input& in, state& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, state& s ) { if( s.minimum_indent > 0 ) { - throw pegtl::parse_error( "expected indented block instead of eof", in ); // NOLINT + throw pegtl::parse_error( "expected indented block instead of eof", in ); } } }; } // namespace example -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { for( int i = 1; i < argc; ++i ) { pegtl::file_input in( argv[ i ] ); diff --git a/packages/PEGTL/src/example/pegtl/json_build.cpp b/packages/PEGTL/src/example/pegtl/json_build.cpp index 7d7b9dc7798250eaf168b21ddc7b3cfb09e21c6c..f4ec3dc9f61b476969531ea45647a23d609fb7f0 100644 --- a/packages/PEGTL/src/example/pegtl/json_build.cpp +++ b/packages/PEGTL/src/example/pegtl/json_build.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cassert> @@ -32,8 +32,7 @@ namespace examples template< typename Rule > struct action - { - }; + {}; template<> struct action< pegtl::json::null > @@ -65,8 +64,8 @@ namespace examples template<> struct action< pegtl::json::number > { - template< typename Input > - static void apply( const Input& in, json_state& state ) + template< typename ActionInput > + static void apply( const ActionInput& in, json_state& state ) { std::stringstream ss( in.string() ); long double v; @@ -79,8 +78,8 @@ namespace examples struct action< pegtl::json::string::content > : json_unescape { - template< typename Input > - static void success( const Input& /*unused*/, std::string& s, json_state& state ) + template< typename ParseInput > + static void success( const ParseInput& /*unused*/, std::string& s, json_state& state ) { state.result = std::make_shared< string_json >( std::move( s ) ); } @@ -129,8 +128,8 @@ namespace examples struct action< pegtl::json::key::content > : json_unescape { - template< typename Input > - static void success( const Input& /*unused*/, std::string& s, json_state& state ) + template< typename ParseInput > + static void success( const ParseInput& /*unused*/, std::string& s, json_state& state ) { state.keys.push_back( std::move( s ) ); } @@ -160,7 +159,7 @@ namespace examples } // namespace examples -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { if( argc != 2 ) { std::cerr << "usage: " << argv[ 0 ] << " <json>"; @@ -168,7 +167,7 @@ int main( int argc, char** argv ) else { examples::json_state state; pegtl::file_input in( argv[ 1 ] ); - pegtl::parse< examples::grammar, examples::action, examples::errors >( in, state ); + pegtl::parse< examples::grammar, examples::action, examples::control >( in, state ); assert( state.keys.empty() ); assert( state.arrays.empty() ); assert( state.objects.empty() ); diff --git a/packages/PEGTL/src/example/pegtl/json_classes.hpp b/packages/PEGTL/src/example/pegtl/json_classes.hpp index 0e5567e95911cb3e2fe19268762048f30a79c1db..8513ec804d8aa2d6913778467bc676bbec8a40a8 100644 --- a/packages/PEGTL/src/example/pegtl/json_classes.hpp +++ b/packages/PEGTL/src/example/pegtl/json_classes.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_CLASSES_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_CLASSES_HPP #define TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_CLASSES_HPP #include <iostream> @@ -27,8 +27,7 @@ namespace examples protected: explicit json_base( const json_type in_type ) : type( in_type ) - { - } + {} virtual ~json_base() = default; @@ -60,8 +59,7 @@ namespace examples { array_json() : json_base( json_type::array ) - { - } + {} std::vector< std::shared_ptr< json_base > > data; @@ -85,8 +83,7 @@ namespace examples explicit boolean_json( const bool in_data ) : json_base( json_type::boolean ), data( in_data ) - { - } + {} bool data; @@ -101,8 +98,7 @@ namespace examples { null_json() : json_base( json_type::null ) - { - } + {} void stream( std::ostream& o ) const override { @@ -116,8 +112,7 @@ namespace examples explicit number_json( const long double in_data ) : json_base( json_type::number ), data( in_data ) - { - } + {} long double data; @@ -135,7 +130,7 @@ namespace examples static const char* h = "0123456789abcdef"; - const auto* d = static_cast< const unsigned char* >( static_cast< const void* >( data.data() ) ); + const auto* d = reinterpret_cast< const unsigned char* >( data.data() ); for( std::size_t i = 0; i < data.size(); ++i ) { switch( const auto c = d[ i ] ) { @@ -178,11 +173,10 @@ namespace examples struct string_json : public json_base { - explicit string_json( const std::string& in_data ) // NOLINT + explicit string_json( const std::string& in_data ) : json_base( json_type::string ), data( in_data ) - { - } + {} std::string data; @@ -197,8 +191,7 @@ namespace examples { object_json() : json_base( json_type::object ) - { - } + {} std::map< std::string, std::shared_ptr< json_base > > data; diff --git a/packages/PEGTL/src/example/pegtl/json_count.cpp b/packages/PEGTL/src/example/pegtl/json_count.cpp index 7b6cd295bab057ff7a770cbbc2bbaed1f5f83548..e0fb731afaf1c260f367d49dbc8adcb8b35a80a0 100644 --- a/packages/PEGTL/src/example/pegtl/json_count.cpp +++ b/packages/PEGTL/src/example/pegtl/json_count.cpp @@ -1,20 +1,60 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ +#include <cstddef> #include <iomanip> #include <iostream> - -#define TAO_PEGTL_PRETTY_DEMANGLE +#include <map> +#include <string_view> #include <tao/pegtl.hpp> -#include <tao/pegtl/contrib/counter.hpp> + #include <tao/pegtl/contrib/json.hpp> -#include <tao/pegtl/file_input.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +namespace TAO_PEGTL_NAMESPACE +{ + struct counter_data + { + std::size_t start = 0; + std::size_t success = 0; + std::size_t failure = 0; + }; + + struct counter_state + { + std::map< std::string_view, counter_data > counts; + }; + + template< typename Rule > + struct counter + : normal< Rule > + { + template< typename Input > + static void start( const Input& /*unused*/, counter_state& ts ) + { + ++ts.counts[ internal::demangle< Rule >() ].start; + } + + template< typename Input > + static void success( const Input& /*unused*/, counter_state& ts ) + { + ++ts.counts[ internal::demangle< Rule >() ].success; + } + + template< typename Input > + static void failure( const Input& /*unused*/, counter_state& ts ) + { + ++ts.counts[ internal::demangle< Rule >() ].failure; + } + }; + +} // namespace TAO_PEGTL_NAMESPACE + +using namespace TAO_PEGTL_NAMESPACE; + using grammar = must< json::text, eof >; -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { counter_state cs; diff --git a/packages/PEGTL/src/example/pegtl/json_coverage.cpp b/packages/PEGTL/src/example/pegtl/json_coverage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b19c496929c3f5ce0cb3ad07c00599ed1b1b8c60 --- /dev/null +++ b/packages/PEGTL/src/example/pegtl/json_coverage.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#include <iostream> + +#include <tao/pegtl.hpp> + +#include <tao/pegtl/contrib/coverage.hpp> +#include <tao/pegtl/contrib/json.hpp> +#include <tao/pegtl/contrib/print_coverage.hpp> + +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) +{ + for( int i = 1; i < argc; ++i ) { + auto coverage = tao::pegtl::coverage< tao::pegtl::json::text >( tao::pegtl::file_input( argv[ i ] ) ); + tao::pegtl::print_coverage( std::cout, coverage ); + } + return 0; +} diff --git a/packages/PEGTL/src/example/pegtl/json_errors.hpp b/packages/PEGTL/src/example/pegtl/json_errors.hpp index 07067cf3e829cf09c95f20317a26b9f60239606a..4f674f805188bfd015944c3dcd30f325e4e2a8d7 100644 --- a/packages/PEGTL/src/example/pegtl/json_errors.hpp +++ b/packages/PEGTL/src/example/pegtl/json_errors.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_ERRORS_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_ERRORS_HPP #define TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_ERRORS_HPP #include <tao/pegtl.hpp> @@ -12,53 +12,38 @@ namespace pegtl = TAO_PEGTL_NAMESPACE; namespace examples { // This file shows how to throw exceptions with - // custom error messages for parse errors. A custom - // control class is created that delegates everything - // to the PEGTL default control class TAO_PEGTL_NAMESPACE::normal<> - // except for the throwing of exceptions: + // custom error messages for parse errors. + // As the grammar contains must<>-rules, + // the compiler will complain when a + // specialization is missing. - template< typename Rule > - struct errors - : public pegtl::normal< Rule > - { - static const std::string error_message; + // clang-format off + template< typename > inline constexpr const char* error_message = nullptr; - template< typename Input, typename... States > - static void raise( const Input& in, States&&... /*unused*/ ) - { - throw pegtl::parse_error( error_message, in ); - } - }; + template<> inline constexpr auto error_message< pegtl::json::text > = "no valid JSON"; - // The following specialisations of the static string - // member are then used in the exception messages: + template<> inline constexpr auto error_message< pegtl::json::end_array > = "incomplete array, expected ']'"; + template<> inline constexpr auto error_message< pegtl::json::end_object > = "incomplete object, expected '}'"; + template<> inline constexpr auto error_message< pegtl::json::member > = "expected member"; + template<> inline constexpr auto error_message< pegtl::json::name_separator > = "expected ':'"; + template<> inline constexpr auto error_message< pegtl::json::array_element > = "expected value"; + template<> inline constexpr auto error_message< pegtl::json::value > = "expected value"; - // clang-format off - template<> inline const std::string errors< pegtl::json::text >::error_message = "no valid JSON"; // NOLINT + template<> inline constexpr auto error_message< pegtl::json::digits > = "expected at least one digit"; + template<> inline constexpr auto error_message< pegtl::json::xdigit > = "incomplete universal character name"; + template<> inline constexpr auto error_message< pegtl::json::escaped > = "unknown escape sequence"; + template<> inline constexpr auto error_message< pegtl::json::char_ > = "invalid character in string"; + template<> inline constexpr auto error_message< pegtl::json::string::content > = "unterminated string"; + template<> inline constexpr auto error_message< pegtl::json::key::content > = "unterminated key"; - template<> inline const std::string errors< pegtl::json::end_array >::error_message = "incomplete array, expected ']'"; // NOLINT - template<> inline const std::string errors< pegtl::json::end_object >::error_message = "incomplete object, expected '}'"; // NOLINT - template<> inline const std::string errors< pegtl::json::member >::error_message = "expected member"; // NOLINT - template<> inline const std::string errors< pegtl::json::name_separator >::error_message = "expected ':'"; // NOLINT - template<> inline const std::string errors< pegtl::json::array_element >::error_message = "expected value"; // NOLINT - template<> inline const std::string errors< pegtl::json::value >::error_message = "expected value"; // NOLINT + template<> inline constexpr auto error_message< pegtl::eof > = "unexpected character after JSON value"; - template<> inline const std::string errors< pegtl::json::digits >::error_message = "expected at least one digit"; // NOLINT - template<> inline const std::string errors< pegtl::json::xdigit >::error_message = "incomplete universal character name"; // NOLINT - template<> inline const std::string errors< pegtl::json::escaped >::error_message = "unknown escape sequence"; // NOLINT - template<> inline const std::string errors< pegtl::json::char_ >::error_message = "invalid character in string"; // NOLINT - template<> inline const std::string errors< pegtl::json::string::content >::error_message = "unterminated string"; // NOLINT - template<> inline const std::string errors< pegtl::json::key::content >::error_message = "unterminated key"; // NOLINT + // As must_if can not take error_message as a template parameter directly, we need to wrap it: + struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; }; - template<> inline const std::string errors< pegtl::eof >::error_message = "unexpected character after JSON value"; // NOLINT + template< typename Rule > using control = pegtl::must_if< error >::control< Rule >; // clang-format on - // The raise()-function-template is instantiated exactly - // for the specialisations of errors< Rule > for which a - // parse error can be generated, therefore the string - // error_message needs to be supplied only for these rules - // (and the compiler will complain if one is missing). - } // namespace examples #endif diff --git a/packages/PEGTL/src/example/pegtl/json_parse.cpp b/packages/PEGTL/src/example/pegtl/json_parse.cpp index 65f62b21a70766fab1369a56dc21119fe912877e..7db715bcc5314983cda4d7808c0bad1f6047e6b5 100644 --- a/packages/PEGTL/src/example/pegtl/json_parse.cpp +++ b/packages/PEGTL/src/example/pegtl/json_parse.cpp @@ -1,18 +1,18 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <tao/pegtl.hpp> #include "json_errors.hpp" -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; using grammar = must< json::text, eof >; -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { for( int i = 1; i < argc; ++i ) { argv_input in( argv, i ); - parse< grammar, nothing, examples::errors >( in ); + parse< grammar, nothing, examples::control >( in ); } return 0; } diff --git a/packages/PEGTL/src/example/pegtl/json_print_rules.cpp b/packages/PEGTL/src/example/pegtl/json_print_rules.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87850508fe761c236314a356b174f8d617a54146 --- /dev/null +++ b/packages/PEGTL/src/example/pegtl/json_print_rules.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#include <iostream> + +#include <tao/pegtl/contrib/json.hpp> +#include <tao/pegtl/contrib/print.hpp> + +int main() // NOLINT(bugprone-exception-escape) +{ + tao::pegtl::print_rules< tao::pegtl::json::text >( std::cout ); + return 0; +} diff --git a/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp b/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e28a04ef9fd3cd6ecd1fb0ca211be35401749f71 --- /dev/null +++ b/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#include <iostream> + +#include <tao/pegtl/contrib/json.hpp> +#include <tao/pegtl/contrib/print.hpp> + +int main() // NOLINT(bugprone-exception-escape) +{ + tao::pegtl::print_sub_rules< tao::pegtl::json::text >( std::cout ); + return 0; +} diff --git a/packages/PEGTL/src/example/pegtl/json_unescape.hpp b/packages/PEGTL/src/example/pegtl/json_unescape.hpp index 09be84f2cd6cb1eaccc07b21c23c28c081b341d1..974c6afb77f46aa04614f8fb629c45fd41b4175d 100644 --- a/packages/PEGTL/src/example/pegtl/json_unescape.hpp +++ b/packages/PEGTL/src/example/pegtl/json_unescape.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_UNESCAPE_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_UNESCAPE_HPP #define TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_UNESCAPE_HPP #include <string> diff --git a/packages/PEGTL/src/example/pegtl/lua53_parse.cpp b/packages/PEGTL/src/example/pegtl/lua53_parse.cpp index 70449f4fef49993aa7f631a3a274530e5f311368..ddb1df06b2c75ac04874ec1fc074e49a0cb81469 100644 --- a/packages/PEGTL/src/example/pegtl/lua53_parse.cpp +++ b/packages/PEGTL/src/example/pegtl/lua53_parse.cpp @@ -1,8 +1,8 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <tao/pegtl.hpp> -#include <tao/pegtl/analyze.hpp> +#include <tao/pegtl/contrib/analyze.hpp> #include <tao/pegtl/contrib/raw_string.hpp> namespace lua53 @@ -333,7 +333,7 @@ namespace lua53 } // namespace lua53 -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { if( TAO_PEGTL_NAMESPACE::analyze< lua53::grammar >() != 0 ) { return 1; diff --git a/packages/PEGTL/src/example/pegtl/modulus_match.cpp b/packages/PEGTL/src/example/pegtl/modulus_match.cpp index 76c8394d7b38b4fbe86975c7b7bfa2e0546df8b9..e748a1940eb8beb72af3392f44a860d8a0143301 100644 --- a/packages/PEGTL/src/example/pegtl/modulus_match.cpp +++ b/packages/PEGTL/src/example/pegtl/modulus_match.cpp @@ -1,22 +1,20 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <tao/pegtl.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; namespace modulus { template< unsigned M, unsigned R = 0 > struct my_rule { - using analyze_t = analysis::generic< analysis::rule_type::any >; - static_assert( M > 1, "Modulus must be greater than 1" ); static_assert( R < M, "Remainder must be less than modulus" ); - template< typename Input > - static bool match( Input& in ) + template< typename ParseInput > + static bool match( ParseInput& in ) { if( !in.empty() ) { if( ( ( *in.current() ) % M ) == R ) { @@ -30,12 +28,11 @@ namespace modulus struct grammar : until< eolf, must< my_rule< 3 > > > - { - }; + {}; } // namespace modulus -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { if( argc > 1 ) { argv_input in( argv, 1 ); diff --git a/packages/PEGTL/src/example/pegtl/parse_tree.cpp b/packages/PEGTL/src/example/pegtl/parse_tree.cpp index 3e5f6ee741458d07681cb3e3cefd5094c86ec67f..9f0053f225a5d2bce91c51ce0e6489edf8d93547 100644 --- a/packages/PEGTL/src/example/pegtl/parse_tree.cpp +++ b/packages/PEGTL/src/example/pegtl/parse_tree.cpp @@ -1,6 +1,7 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ +#include <array> #include <iostream> #include <string> #include <type_traits> @@ -9,7 +10,7 @@ #include <tao/pegtl/contrib/parse_tree.hpp> #include <tao/pegtl/contrib/parse_tree_to_dot.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; namespace example { @@ -55,8 +56,8 @@ namespace example // if only one child is left for LHS..., replace the PROD/EXPR with the child directly. // otherwise, perform the above transformation, then apply it recursively until LHS... // becomes a single child, which then replaces the parent node and the recursion ends. - template< typename... States > - static void transform( std::unique_ptr< parse_tree::node >& n, States&&... st ) + template< typename Node, typename... States > + static void transform( std::unique_ptr< Node >& n, States&&... st ) { if( n->children.size() == 1 ) { n = std::move( n->children.back() ); @@ -93,6 +94,69 @@ namespace example product, expression > >; + namespace internal + { + // a non-thread-safe allocation cache, assuming that the size (sz) is always the same! + template< std::size_t N > + struct cache + { + std::size_t pos = 0; + std::array< void*, N > data; + + cache() = default; + + cache( const cache& ) = delete; + cache( cache&& ) = delete; + + ~cache() + { + while( pos != 0 ) { + ::operator delete( data[ --pos ] ); + } + } + + cache& operator=( const cache& ) = delete; + cache& operator=( cache&& ) = delete; + + void* get( std::size_t sz ) + { + if( pos != 0 ) { + return data[ --pos ]; + } + return ::operator new( sz ); + } + + void put( void* p ) + { + if( pos < N ) { + data[ pos++ ] = p; + } + else { + ::operator delete( p ); + } + } + }; + + static cache< 32 > the_cache; + + } // namespace internal + + // this is not necessary for the example, but serves as a demonstration for an additional optimization. + struct node + : parse_tree::basic_node< node > + { + void* operator new( std::size_t sz ) + { + assert( sz == sizeof( node ) ); + return internal::the_cache.get( sz ); + } + + void operator delete( void* p ) + { + internal::the_cache.put( p ); + } + }; + } // namespace example int main( int argc, char** argv ) @@ -105,7 +169,7 @@ int main( int argc, char** argv ) } argv_input in( argv, 1 ); try { - const auto root = parse_tree::parse< example::grammar, example::selector >( in ); + const auto root = parse_tree::parse< example::grammar, example::node, example::selector >( in ); parse_tree::print_dot( std::cout, *root ); return 0; } @@ -118,5 +182,6 @@ int main( int argc, char** argv ) catch( const std::exception& e ) { std::cerr << e.what() << std::endl; } + return 1; } diff --git a/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp b/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp index 6b207c062bda56e21e1519ed356af95c15e60967..e6baa01cdabbbc5813a3e1c769b4e8d182b8ccd2 100644 --- a/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp +++ b/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <type_traits> @@ -6,7 +6,7 @@ #include <tao/pegtl.hpp> #include <tao/pegtl/contrib/parse_tree.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; template< typename > using selector = std::true_type; @@ -21,8 +21,8 @@ struct work template<> struct work< success > { - template< typename Input > - static void apply( const Input& /*unused*/, user_state& /*unused*/ ) + template< typename ActionInput > + static void apply( const ActionInput& /*unused*/, user_state& /*unused*/ ) {} }; diff --git a/packages/PEGTL/src/example/pegtl/proto3.cpp b/packages/PEGTL/src/example/pegtl/proto3.cpp index a1b6f281b68b7c9ad5b17160f86ddc544fc58d23..2797187882ecd123bab1c097fa74d572af0f3d5f 100644 --- a/packages/PEGTL/src/example/pegtl/proto3.cpp +++ b/packages/PEGTL/src/example/pegtl/proto3.cpp @@ -1,10 +1,8 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#define TAO_PEGTL_PRETTY_DEMANGLE 1 - #include <tao/pegtl.hpp> -#include <tao/pegtl/analyze.hpp> +#include <tao/pegtl/contrib/analyze.hpp> namespace TAO_PEGTL_NAMESPACE::proto3 { @@ -98,9 +96,9 @@ namespace TAO_PEGTL_NAMESPACE::proto3 struct enum_value_option : seq< option_name, sps, equ, sps, constant > {}; struct enum_field : seq< ident, sps, equ, sps, int_lit, sps, opt_must< one< '[' >, sps, list_must< enum_value_option, comma, sp >, sps, one< ']' >, sps >, semi > {}; struct enum_body : if_must< one< '{' >, sps, star< sor< option, enum_field, semi >, sps >, one< '}' > > {}; - struct enum_ : if_must< string< 'e', 'n', 'u', 'm' >, sps, enum_name, sps, enum_body > {}; + struct enum_def : if_must< string< 'e', 'n', 'u', 'm' >, sps, enum_name, sps, enum_body > {}; - struct message_thing : sor< field, enum_, message, option, oneof, map_field, reserved, semi > {}; + struct message_thing : sor< field, enum_def, message, option, oneof, map_field, reserved, semi > {}; struct message : if_must< string< 'm', 'e', 's', 's', 'a', 'g', 'e' >, sps, ident, sps, one< '{' >, sps, star< message_thing, sps >, one< '}' >, sps > {}; struct package : if_must< string< 'p', 'a', 'c', 'k', 'a', 'g', 'e' >, sps, full_ident, sps, semi, sps > {}; @@ -115,7 +113,7 @@ namespace TAO_PEGTL_NAMESPACE::proto3 struct service_name : ident {}; struct service : if_must< string< 's', 'e', 'r', 'v', 'i', 'c', 'e' >, sps, service_name, sps, one< '{' >, sps, list_must< sor< option, rpc, semi >, comma, sp >, sps, one< '}' > > {}; - struct body : sor< import, package, option, message, enum_, service, semi > {}; + struct body : sor< import, package, option, message, enum_def, service, semi > {}; struct head : if_must< string< 's', 'y', 'n', 't', 'a', 'x' >, sps, equ, sps, string< '"', 'p', 'r', 'o', 't', 'o', '3', '"' >, sps, semi > {}; struct proto : must< sps, head, sps, star< body, sps >, eof > {}; @@ -124,9 +122,9 @@ namespace TAO_PEGTL_NAMESPACE::proto3 } // namespace TAO_PEGTL_NAMESPACE::proto3 -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { - using namespace TAO_PEGTL_NAMESPACE; // NOLINT + using namespace TAO_PEGTL_NAMESPACE; if( analyze< proto3::proto >() != 0 ) { return 1; diff --git a/packages/PEGTL/src/example/pegtl/recover.cpp b/packages/PEGTL/src/example/pegtl/recover.cpp index c39dcc1179281c3a3049a4e2d25ed3271c61f3d4..6353a7442074a645a105e31999a2400bd3331adb 100644 --- a/packages/PEGTL/src/example/pegtl/recover.cpp +++ b/packages/PEGTL/src/example/pegtl/recover.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ // This is a small experiment with a grammar that can recover from errors. @@ -16,7 +16,7 @@ #include <tao/pegtl.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; // clang-format off @@ -52,8 +52,8 @@ struct my_action template< typename T > struct my_action< skipping< T > > { - template< typename Input > - static void apply( const Input& in, bool& error ) + template< typename ActionInput > + static void apply( const ActionInput& in, bool& error ) { if( !error ) { std::cout << in.position() << ": Invalid expression \"" << in.string() << "\"" << std::endl; @@ -65,8 +65,8 @@ struct my_action< skipping< T > > template< typename R > struct found { - template< typename Input > - static void apply( const Input& in, bool& error ) + template< typename ActionInput > + static void apply( const ActionInput& in, bool& error ) { if( !error ) { std::cout << in.position() << ": Found " << internal::demangle< R >() << ": \"" << in.string() << "\"" << std::endl; @@ -88,8 +88,8 @@ template<> struct my_action< expr > : found< expr > {}; template<> struct my_action< recoverable_expr > { - template< typename Input > - static void apply( const Input& /*unused*/, bool& error ) + template< typename ActionInput > + static void apply( const ActionInput& /*unused*/, bool& error ) { error = false; std::cout << std::string( 79, '-' ) << std::endl; @@ -100,11 +100,11 @@ template< typename Rule > struct my_control : normal< Rule > { - template< typename Input, typename... States > - static void raise( const Input& in, States&&... /*unused*/ ) + template< typename ParseInput, typename... States > + [[noreturn]] static void raise( const ParseInput& in, States&&... /*unused*/ ) { std::cout << in.position() << ": Parse error matching " << internal::demangle< Rule >() << std::endl; - throw parse_error( "parse error matching " + internal::demangle< Rule >(), in ); + throw parse_error( "parse error matching " + std::string( internal::demangle< Rule >() ), in ); } }; diff --git a/packages/PEGTL/src/example/pegtl/s_expression.cpp b/packages/PEGTL/src/example/pegtl/s_expression.cpp index c99311f8d89722ad14a3435ba7947e761a692fac..7c47f1c8b9b11217a070b5ac6d8355beca569f02 100644 --- a/packages/PEGTL/src/example/pegtl/s_expression.cpp +++ b/packages/PEGTL/src/example/pegtl/s_expression.cpp @@ -1,12 +1,12 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <iostream> #include <tao/pegtl.hpp> -#include <tao/pegtl/analyze.hpp> +#include <tao/pegtl/contrib/analyze.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; namespace sexpr { @@ -44,8 +44,8 @@ namespace sexpr template<> struct action< plus< not_one< '"' > > > { - template< typename Input > - static void apply( const Input& in, std::string& fn ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& fn ) { fn = in.string(); } @@ -54,8 +54,8 @@ namespace sexpr template<> struct action< hash_include > { - template< typename Input > - static void apply( const Input& in, std::string& fn ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& fn ) { std::string f2; // Here f2 is the state argument for the nested parsing @@ -71,7 +71,7 @@ namespace sexpr } // namespace sexpr -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { if( analyze< sexpr::main >() != 0 ) { return 1; diff --git a/packages/PEGTL/src/example/pegtl/sum.cpp b/packages/PEGTL/src/example/pegtl/sum.cpp index 25b2484f50bac80a5171fa3f5a9c309dcc5c4007..196a2a87dd23370e0db1f3a8e82ba2dbdd897405 100644 --- a/packages/PEGTL/src/example/pegtl/sum.cpp +++ b/packages/PEGTL/src/example/pegtl/sum.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cstdlib> @@ -8,7 +8,7 @@ #include <tao/pegtl.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; #include "double.hpp" @@ -33,8 +33,8 @@ namespace sum template<> struct action< double_::grammar > { - template< typename Input > - static void apply( const Input& in, double& sum ) + template< typename ActionInput > + static void apply( const ActionInput& in, double& sum ) { // assume all values will fit into a C++ double std::stringstream ss( in.string() ); diff --git a/packages/PEGTL/src/example/pegtl/symbol_table.cpp b/packages/PEGTL/src/example/pegtl/symbol_table.cpp index fce5d6e1a364d2efdca25c54f68fe8790ed4ff9b..5d0a7b51ab7a503008cc787c3ade45738dcf4af2 100644 --- a/packages/PEGTL/src/example/pegtl/symbol_table.cpp +++ b/packages/PEGTL/src/example/pegtl/symbol_table.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cstring> @@ -47,7 +47,7 @@ namespace example template<> struct action< value > - : public pegtl::integer::unsigned_action + : public pegtl::unsigned_action { // Sets st.converted to the integer value of the matched string. }; @@ -55,8 +55,8 @@ namespace example template<> struct action< name > { - template< typename Input > - static void apply( const Input& in, state& st ) + template< typename ActionInput > + static void apply( const ActionInput& in, state& st ) { st.temporary = in.string(); } @@ -65,11 +65,11 @@ namespace example template<> struct action< definition > { - template< typename Input > - static void apply( const Input& in, state& st ) + template< typename ActionInput > + static void apply( const ActionInput& in, state& st ) { - if( !st.symbol_table.emplace( st.temporary, 0 ).second ) { - throw pegtl::parse_error( "duplicate symbol " + st.temporary, in ); // NOLINT + if( !st.symbol_table.try_emplace( st.temporary, 0 ).second ) { + throw pegtl::parse_error( "duplicate symbol " + st.temporary, in ); } } }; @@ -77,12 +77,12 @@ namespace example template<> struct action< assignment > { - template< typename Input > - static void apply( const Input& in, state& st ) + template< typename ActionInput > + static void apply( const ActionInput& in, state& st ) { const auto i = st.symbol_table.find( st.temporary ); if( i == st.symbol_table.end() ) { - throw pegtl::parse_error( "unknown symbol " + st.temporary, in ); // NOLINT + throw pegtl::parse_error( "unknown symbol " + st.temporary, in ); } i->second = st.converted; } @@ -90,7 +90,7 @@ namespace example } // namespace example -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { for( int i = 1; i < argc; ++i ) { pegtl::file_input in( argv[ i ] ); diff --git a/packages/PEGTL/src/example/pegtl/unescape.cpp b/packages/PEGTL/src/example/pegtl/unescape.cpp index 69705ca340ab21c329886285339c98193a0bbec7..8296ce0400b8b68ca827fcb2cf491b735f9c968d 100644 --- a/packages/PEGTL/src/example/pegtl/unescape.cpp +++ b/packages/PEGTL/src/example/pegtl/unescape.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <iostream> @@ -7,7 +7,7 @@ #include <tao/pegtl/contrib/unescape.hpp> -using namespace TAO_PEGTL_NAMESPACE; // NOLINT +using namespace TAO_PEGTL_NAMESPACE; namespace example { @@ -48,7 +48,7 @@ namespace example } // namespace example -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { for( int i = 1; i < argc; ++i ) { std::string s; diff --git a/packages/PEGTL/src/example/pegtl/uri.cpp b/packages/PEGTL/src/example/pegtl/uri.cpp index f504b68cf177e69b43dd50eb222b369d7bd70074..38559c574b1c0f928248b42786c05b5225731ca0 100644 --- a/packages/PEGTL/src/example/pegtl/uri.cpp +++ b/packages/PEGTL/src/example/pegtl/uri.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <tao/pegtl.hpp> @@ -27,8 +27,8 @@ namespace uri template< std::string URI::*Field > struct bind { - template< typename Input > - static void apply( const Input& in, URI& uri ) + template< typename ActionInput > + static void apply( const ActionInput& in, URI& uri ) { uri.*Field = in.string(); } @@ -53,8 +53,8 @@ namespace uri template<> struct action< pegtl::uri::opt_userinfo > { - template< typename Input > - static void apply( const Input& in, URI& uri ) + template< typename ActionInput > + static void apply( const ActionInput& in, URI& uri ) { if( !in.empty() ) { uri.userinfo = std::string( in.begin(), in.size() - 1 ); diff --git a/packages/PEGTL/src/example/pegtl/uri_trace.cpp b/packages/PEGTL/src/example/pegtl/uri_trace.cpp index 1d09e9fa5ef9a899575df80bd38e1033122b6c77..cbd354ef15277ed3d126633757fd0adcc9316bc3 100644 --- a/packages/PEGTL/src/example/pegtl/uri_trace.cpp +++ b/packages/PEGTL/src/example/pegtl/uri_trace.cpp @@ -1,22 +1,22 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <iostream> #include <tao/pegtl.hpp> -#include <tao/pegtl/contrib/tracer.hpp> +#include <tao/pegtl/contrib/trace.hpp> #include <tao/pegtl/contrib/uri.hpp> namespace pegtl = TAO_PEGTL_NAMESPACE; using grammar = pegtl::must< pegtl::uri::URI >; -int main( int argc, char** argv ) +int main( int argc, char** argv ) // NOLINT(bugprone-exception-escape) { for( int i = 1; i < argc; ++i ) { std::cout << "Parsing " << argv[ i ] << std::endl; pegtl::argv_input in( argv, i ); - pegtl::parse< grammar, pegtl::nothing, pegtl::tracer >( in ); + pegtl::parse< grammar, pegtl::nothing, pegtl::trace_control >( in ); } return 0; } diff --git a/packages/PEGTL/src/test/pegtl/CMakeLists.txt b/packages/PEGTL/src/test/pegtl/CMakeLists.txt index fda805afb0fa5ed505485d9d3ac397fefeb264cb..964d99432ce8e434ccc7e807aaec5aaeb376cf92 100644 --- a/packages/PEGTL/src/test/pegtl/CMakeLists.txt +++ b/packages/PEGTL/src/test/pegtl/CMakeLists.txt @@ -6,7 +6,6 @@ set(test_sources actions_one.cpp actions_three.cpp actions_two.cpp - analyze_cycles.cpp argv_input.cpp ascii_classes.cpp ascii_eol.cpp @@ -25,8 +24,10 @@ set(test_sources change_state.cpp change_states.cpp contrib_alphabet.cpp - contrib_integer.cpp + contrib_analyze.cpp + contrib_http.cpp contrib_if_then.cpp + contrib_integer.cpp contrib_json.cpp contrib_parse_tree.cpp contrib_partial_trace.cpp @@ -39,6 +40,7 @@ set(test_sources data_cstring.cpp demangle.cpp discard_input.cpp + error_message.cpp file_cstream.cpp file_file.cpp file_istream.cpp @@ -125,9 +127,9 @@ foreach(testsourcefile ${test_sources}) target_compile_options(${exename} PRIVATE -pedantic -Wall -Wextra -Wshadow -Werror) endif() if(ANDROID) - add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. COMMAND ${CMAKE_COMMAND} -DANDROID_NDK=${ANDROID_NDK} "-DTEST_RESOURCES=src/test/pegtl/data;src/test/pegtl/file_data.txt;Makefile" -DTEST_RESOURCES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/../../.. -DUNITTEST=${CMAKE_CURRENT_BINARY_DIR}/${exename} -DTEST_PARAMETER=-all -P ${CMAKE_CURRENT_SOURCE_DIR}/ExecuteOnAndroid.cmake) + add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} "-DANDROID_NDK=${ANDROID_NDK}" "-DTEST_RESOURCES_DIR=${CMAKE_SOURCE_DIR}" "-DTEST_RESOURCES=src/test/pegtl/data;src/test/pegtl/file_data.txt;Makefile" "-DUNITTEST=${exename}" -P ${CMAKE_CURRENT_SOURCE_DIR}/ExecuteOnAndroid.cmake) else() - add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. COMMAND ${exename}) + add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${exename}) endif() endforeach(testsourcefile) diff --git a/packages/PEGTL/src/test/pegtl/ExecuteOnAndroid.cmake b/packages/PEGTL/src/test/pegtl/ExecuteOnAndroid.cmake index 7f15007d04739e545018fba8b0081f5d38fc36af..e2ccfe97ecc5bb00e5a156e47b52f19761829e2b 100644 --- a/packages/PEGTL/src/test/pegtl/ExecuteOnAndroid.cmake +++ b/packages/PEGTL/src/test/pegtl/ExecuteOnAndroid.cmake @@ -1,4 +1,12 @@ +if("${ANDROID_NDK}" STREQUAL "") + message(FATAL_ERROR "cmake parameter ANDROID_NDK is not set!") +endif() + +if(NOT EXISTS "${ANDROID_NDK}/../platform-tools/adb") + message(FATAL_ERROR "adb is not found in ${ANDROID_NDK}/../platform-tools") +endif() + get_filename_component(UNITTEST_FILENAME ${UNITTEST} NAME) message(STATUS "Cleanup /data/local/tmp ...") execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "rm -r /data/local/tmp/*" OUTPUT_QUIET) @@ -6,24 +14,28 @@ execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "rm -r /data/ foreach(_TEST_DATA IN ITEMS ${TEST_RESOURCES}) get_filename_component(_DIR ${_TEST_DATA} DIRECTORY) message(STATUS "Create /data/local/tmp/${_DIR} directory structure on android ...") - execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "mkdir -p /data/local/tmp/${_DIR}" OUTPUT_QUIET) - message(STATUS "Push ${_TEST_DATA} to android ...") + execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "mkdir -p /data/local/tmp/${_DIR}" OUTPUT_QUIET) + message(STATUS "Push ${_TEST_DATA} from ${TEST_RESOURCES_DIR} to android ...") execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb push ${_TEST_DATA} /data/local/tmp/${_DIR} OUTPUT_QUIET WORKING_DIRECTORY ${TEST_RESOURCES_DIR}) endforeach() if(LIBRARY_DIR) message(STATUS "Push ${LIBRARY_DIR} to android ...") - execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb push ${LIBRARY_DIR} /data/local/tmp/ OUTPUT_QUIET) + execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb push ${LIBRARY_DIR} /data/local/tmp/ OUTPUT_QUIET) endif() message(STATUS "Push ${UNITTEST} to android ...") +if(NOT EXISTS "${UNITTEST}") + message(FATAL_ERROR "${UNITTEST} is not found!") +endif() execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb push ${UNITTEST} /data/local/tmp/ OUTPUT_QUIET) -message(STATUS "Execute ${UNITTEST_FILENAME} ${TEST_PARAMETER} on android ...") +message(STATUS "Execute ${UNITTEST_FILENAME} on android ...") + execute_process( - COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "cd /data/local/tmp;su root sh -c 'LD_LIBRARY_PATH=/data/local/tmp/lib TMPDIR=/data/local/tmp HOME=/data/local/tmp ./${UNITTEST_FILENAME} ${TEST_PARAMETER};echo exit code $?'" + COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "cd /data/local/tmp;su root sh -c 'LD_LIBRARY_PATH=/data/local/tmp/lib TMPDIR=/data/local/tmp HOME=/data/local/tmp ./${UNITTEST_FILENAME};echo exit code $?'" RESULT_VARIABLE _RESULT OUTPUT_VARIABLE _OUT ERROR_VARIABLE _ERR ) - + if(_RESULT) message(FATAL_ERROR "Execution of ${UNITTEST_FILENAME} failed") else() diff --git a/packages/PEGTL/src/test/pegtl/action_enable.cpp b/packages/PEGTL/src/test/pegtl/action_enable.cpp index 89890bac351b1828c7f0764ab1e80a1301fc7614..148973c5183350eb0a5ad564d94cfc04d2339d50 100644 --- a/packages/PEGTL/src/test/pegtl/action_enable.cpp +++ b/packages/PEGTL/src/test/pegtl/action_enable.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/action_match.cpp b/packages/PEGTL/src/test/pegtl/action_match.cpp index dfb60c6f4254b8f54e1fead5cacf26c8ac643fd3..c6205367a777f8fd3e982f011a6641e8aa23aecf 100644 --- a/packages/PEGTL/src/test/pegtl/action_match.cpp +++ b/packages/PEGTL/src/test/pegtl/action_match.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -14,9 +14,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - [[nodiscard]] static bool match( Input& in, States&&... /*unused*/ ) + [[nodiscard]] static bool match( ParseInput& in, States&&... /*unused*/ ) { return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in ); } @@ -67,15 +67,15 @@ namespace TAO_PEGTL_NAMESPACE struct action_one_b< grammar_inner > { // used inside of remove_state - template< typename Input > - static void apply( const Input& /*unused*/ ) + template< typename ActionInput > + static void apply( const ActionInput& /*unused*/ ) { ++global_state; } // used outside of remove_state - template< typename Input > - static void apply( const Input& in, state_one& state ) + template< typename ActionInput > + static void apply( const ActionInput& in, state_one& state ) { state.byte_in_line_b += in.input().byte(); } @@ -94,8 +94,8 @@ namespace TAO_PEGTL_NAMESPACE template<> struct action_one_a< grammar_inner > { - template< typename Input > - static void apply( const Input& in, state_one& state ) + template< typename ActionInput > + static void apply( const ActionInput& in, state_one& state ) { state.byte_in_line_a += in.input().byte(); } diff --git a/packages/PEGTL/src/test/pegtl/actions_one.cpp b/packages/PEGTL/src/test/pegtl/actions_one.cpp index 9577fae8ac6b2377c4b68680d074d05b81e6476e..1e5c2f81312439714ad6cd5475cde7480431e370 100644 --- a/packages/PEGTL/src/test/pegtl/actions_one.cpp +++ b/packages/PEGTL/src/test/pegtl/actions_one.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -9,21 +9,21 @@ namespace TAO_PEGTL_NAMESPACE { - std::vector< std::pair< std::string, std::string > > applied; // NOLINT + std::vector< std::pair< std::string, std::string > > applied; namespace test1 { - struct fiz : if_must< at< one< 'a' > >, two< 'a' > > - { - }; + struct fiz + : if_must< at< one< 'a' > >, two< 'a' > > + {}; - struct foo : sor< fiz, one< 'b' > > - { - }; + struct foo + : sor< fiz, one< 'b' > > + {}; - struct bar : until< eof, foo > - { - }; + struct bar + : until< eof, foo > + {}; void test_result() { @@ -57,8 +57,8 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule > struct test_action { - template< typename Input > - static void apply( const Input& in ) + template< typename ActionInput > + static void apply( const ActionInput& in ) { applied.emplace_back( internal::demangle< Rule >(), in.string() ); } diff --git a/packages/PEGTL/src/test/pegtl/actions_three.cpp b/packages/PEGTL/src/test/pegtl/actions_three.cpp index be49391fef1ecd1bb176c32be47f312ee0e184ce..992d655b9dd01d36ee4a5e16325efe568ccdc0f5 100644 --- a/packages/PEGTL/src/test/pegtl/actions_three.cpp +++ b/packages/PEGTL/src/test/pegtl/actions_three.cpp @@ -1,10 +1,32 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" namespace TAO_PEGTL_NAMESPACE { + template< unsigned Size, apply_mode B, rewind_mode N, typename... Rules > + struct test_rule + { + template< apply_mode A, + rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + static bool match( ParseInput& in, States&&... st ) + { + static_assert( A == B, "unexpected apply mode" ); + static_assert( M == N, "unexpected rewind mode" ); + + TAO_PEGTL_TEST_ASSERT( in.size() == Size ); + + return seq< Rules... >::template match< A, M, Action, Control >( in, st... ); + } + }; + namespace test1 { bool apply_result; @@ -20,8 +42,8 @@ namespace TAO_PEGTL_NAMESPACE template<> struct apply_bool_action< grammar > { - template< typename Input > - static bool apply( const Input& /*unused*/ ) + template< typename ActionInput > + static bool apply( const ActionInput& /*unused*/ ) { return apply_result; } diff --git a/packages/PEGTL/src/test/pegtl/actions_two.cpp b/packages/PEGTL/src/test/pegtl/actions_two.cpp index 0d4475a41a904a0934b379abf66ea075b676cdd8..a21d222ff32abb8014c7e0f9a6906298ccf8c2d3 100644 --- a/packages/PEGTL/src/test/pegtl/actions_two.cpp +++ b/packages/PEGTL/src/test/pegtl/actions_two.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -11,23 +11,24 @@ namespace TAO_PEGTL_NAMESPACE { char c; - template< typename Input > - state1( const Input& /*unused*/, std::string& /*unused*/ ) + template< typename ParseInput > + state1( const ParseInput& /*unused*/, std::string& /*unused*/ ) : c() - { - } + {} - template< typename Input > - void success( const Input& /*unused*/, std::string& s ) const + template< typename ParseInput > + void success( const ParseInput& /*unused*/, std::string& s ) const { s += c; } }; - struct fobble : sor< state< state1, alpha >, digit > + struct fobble + : sor< state< state1, alpha >, digit > {}; - struct fibble : until< eof, fobble > + struct fibble + : until< eof, fobble > {}; template< typename Rule > @@ -37,8 +38,8 @@ namespace TAO_PEGTL_NAMESPACE template<> struct action1< alpha > { - template< typename Input > - static void apply( const Input& in, state1& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, state1& s ) { assert( in.size() == 1 ); s.c = in.begin()[ 0 ]; @@ -97,8 +98,8 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule > struct count_action { - template< typename Input > - static void apply( const Input& in ) + template< typename ActionInput > + static void apply( const ActionInput& in ) { TAO_PEGTL_TEST_ASSERT( in.iterator().byte == count_byte ); TAO_PEGTL_TEST_ASSERT( in.iterator().line == count_line ); diff --git a/packages/PEGTL/src/test/pegtl/argv_input.cpp b/packages/PEGTL/src/test/pegtl/argv_input.cpp index da27be5deae571eec8db4cdd6b7c445f3f9cf884..2c649d504e7a5e65c9c2ee1c0fb75de8de7bb89c 100644 --- a/packages/PEGTL/src/test/pegtl/argv_input.cpp +++ b/packages/PEGTL/src/test/pegtl/argv_input.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cstring> @@ -11,9 +11,9 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { - char data[ 12 ]; // NOLINT + char data[ 12 ]; std::memcpy( data, "foo\0bar\0baz", 12 ); - char* argv[] = { data, data + 4, data + 8 }; // NOLINT + char* argv[] = { data, data + 4, data + 8 }; argv_input in( argv, 1 ); TAO_PEGTL_TEST_ASSERT( in.source() == "argv[1]" ); const auto result = parse< string< 'b', 'a', 'r' > >( in ); diff --git a/packages/PEGTL/src/test/pegtl/ascii_classes.cpp b/packages/PEGTL/src/test/pegtl/ascii_classes.cpp index a16a70d0bb6ed7ef24afdfc59d3b3bdd79f02512..c3301af9784c8cdd7dc3312b0945fc4f82452222 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_classes.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_classes.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_eol.cpp b/packages/PEGTL/src/test/pegtl/ascii_eol.cpp index d84eef09d521b79ea55bd2438ead57c04a6cc21e..9724234d375da805ad1ae7de7de235b3ffe0921f 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_eol.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_eol.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp b/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp index 7b94b247503f2868052953e1eb84c7790e297b92..2cb54e528a1390a4e1f1f72490c8fa39344b9f16 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp b/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp index 4e79fdd9df37413eda5c18e0b3e004bb8dbb7341..fcce5471fefbd91eaa0a07bf5b8b2b297e6a3687 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -16,19 +16,19 @@ namespace TAO_PEGTL_NAMESPACE verify_rule< forty_two< 'a' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::local_failure ); } for( std::size_t i = 42; i < 100; ++i ) { - verify_rule< forty_two< 'a' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::success, i - 42 ); + verify_rule< forty_two< 'a' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::success, int( i - 42 ) ); } for( std::size_t i = 0; i < 42; ++i ) { verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::local_failure ); } for( std::size_t i = 42; i < 100; ++i ) { - verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::success, i - 42 ); + verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::success, int( i - 42 ) ); } for( std::size_t i = 0; i < 42; ++i ) { verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'z' ), result_type::local_failure ); } for( std::size_t i = 42; i < 100; ++i ) { - verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'z' ), result_type::success, i - 42 ); + verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'z' ), result_type::success, int( i - 42 ) ); } verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, "azzaazaazaaazzzaaaazzaaazzaazazzzaazzazaza", result_type::success ); } diff --git a/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp b/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp index 059b98bc48701c89e665c8b6cff19e1a5abb078d..3a4fcbceb5cf43451afabe5469e5f91c60052fa1 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_istring.cpp b/packages/PEGTL/src/test/pegtl/ascii_istring.cpp index 06816ae859b9c4f4ba494756a8846f84537988e8..73a9e733fbc181586a27e095cb524354c5239f92 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_istring.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_istring.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp b/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp index 023e3e16d739534be56b2255f094d1e44ac563f9..17746344dbd488e701312e6684a6adb1d1b83e80 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp b/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp index 004852cf77b63b4da70ee2ab76e4baf48fa7f96f..57042c9a2f0c7cae8c188d8f4238e530339f48c5 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_string.cpp b/packages/PEGTL/src/test/pegtl/ascii_string.cpp index a35950391b53dd03a56c5d9f152374d49b997f89..6d24356c9ac5e4d416751f8ffd724710b1ba5d80 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_string.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_string.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_three.cpp b/packages/PEGTL/src/test/pegtl/ascii_three.cpp index 7ee53f663fc573a81ddad01ea6fe997919d4db45..23a9226306333bf57e75311db35c7b0c9634c5c5 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_three.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_three.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/ascii_two.cpp b/packages/PEGTL/src/test/pegtl/ascii_two.cpp index 5bd48d65018608ce00539a9160557927a992b436..020954b185a013a436acb149209f4df77c207788 100644 --- a/packages/PEGTL/src/test/pegtl/ascii_two.cpp +++ b/packages/PEGTL/src/test/pegtl/ascii_two.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/buffer_input.cpp b/packages/PEGTL/src/test/pegtl/buffer_input.cpp index 752aa7251a97a6e680a8ad71d7b6e44643f20b5d..65e696151d038f015aaba5093f47b1a15f24c7d6 100644 --- a/packages/PEGTL/src/test/pegtl/buffer_input.cpp +++ b/packages/PEGTL/src/test/pegtl/buffer_input.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <string> diff --git a/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp b/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp index 52cbaf735de3ff7c41531d54945d3a275c19b022..abbaaa5e1ae2622bf23e30a395188753e19d9cf9 100644 --- a/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp +++ b/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -35,8 +35,8 @@ namespace TAO_PEGTL_NAMESPACE { int v = 0; - template< typename Input > - explicit S( const Input& /*unused*/, int& c ) + template< typename ParseInput > + explicit S( const ParseInput& /*unused*/, int& c ) { if( c == 5 ) { v = 6; @@ -49,8 +49,8 @@ namespace TAO_PEGTL_NAMESPACE } } - template< typename Input > - void success( const Input& /*unused*/, int& c ) + template< typename ParseInput > + void success( const ParseInput& /*unused*/, int& c ) { if( v != 3 ) { throw std::runtime_error( "fail3" ); diff --git a/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp b/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp index 38b889f2cfe56507f9f49aaaa22fe7b3d09665b6..74cb0c976e20d710218c4b9e67a3ff44a94b7142 100644 --- a/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp +++ b/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -41,8 +41,8 @@ namespace TAO_PEGTL_NAMESPACE throw std::runtime_error( "fail2" ); } - template< typename Input > - static void success( const Input& /*unused*/, int& v, int& c ) + template< typename ParseInput > + static void success( const ParseInput& /*unused*/, int& v, int& c ) { if( v != 2 ) { throw std::runtime_error( "fail3" ); diff --git a/packages/PEGTL/src/test/pegtl/change_state.cpp b/packages/PEGTL/src/test/pegtl/change_state.cpp index 32e3da708d2704f66b98081f79ae50d4788a6031..10a64f154e322778f5da2f32be148c72e520b0ca 100644 --- a/packages/PEGTL/src/test/pegtl/change_state.cpp +++ b/packages/PEGTL/src/test/pegtl/change_state.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -31,8 +31,8 @@ namespace TAO_PEGTL_NAMESPACE { int v = 0; - template< typename Input > - explicit S( const Input& /*unused*/, int& c ) + template< typename ParseInput > + explicit S( const ParseInput& /*unused*/, int& c ) { if( c == 5 ) { v = 6; @@ -45,8 +45,8 @@ namespace TAO_PEGTL_NAMESPACE } } - template< typename Input > - void success( const Input& /*unused*/, int& c ) + template< typename ParseInput > + void success( const ParseInput& /*unused*/, int& c ) { if( v != 3 ) { throw std::runtime_error( "fail3" ); diff --git a/packages/PEGTL/src/test/pegtl/change_states.cpp b/packages/PEGTL/src/test/pegtl/change_states.cpp index 0cdeb2d9af712d572fc6836f4700eddb480ef0b5..d6cdbd0a3a374df3dcba1461cb14523cbef6d256 100644 --- a/packages/PEGTL/src/test/pegtl/change_states.cpp +++ b/packages/PEGTL/src/test/pegtl/change_states.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -39,8 +39,8 @@ namespace TAO_PEGTL_NAMESPACE v = 2; } - template< typename Input > - static void success( const Input& /*unused*/, int& v, int& c ) + template< typename ParseInput > + static void success( const ParseInput& /*unused*/, int& v, int& c ) { if( v != 2 ) { throw std::runtime_error( "fail3" ); diff --git a/packages/PEGTL/src/test/pegtl/contrib_alphabet.cpp b/packages/PEGTL/src/test/pegtl/contrib_alphabet.cpp index 4d0e8c35a4418b014ff6a6a6823f17dd84777c1e..fc3275f4261aca4ddecd3533fbac5f64a4549b82 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_alphabet.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_alphabet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/analyze_cycles.cpp b/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp similarity index 58% rename from packages/PEGTL/src/test/pegtl/analyze_cycles.cpp rename to packages/PEGTL/src/test/pegtl/contrib_analyze.cpp index 099fcc4c6dee28a5cb1e5fb89848ebb123af3325..dee2d0408fa9d1188cb7cd556b53625e6092710a 100644 --- a/packages/PEGTL/src/test/pegtl/analyze_cycles.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -6,125 +6,81 @@ namespace TAO_PEGTL_NAMESPACE { - template< typename... Rules > - struct any_seq - : public seq< Rules... > - { - using analyze_t = analysis::generic< analysis::rule_type::any, Rules... >; - }; - void unit_test() { verify_analyze< eof >( __LINE__, __FILE__, false, false ); verify_analyze< eolf >( __LINE__, __FILE__, false, false ); verify_analyze< success >( __LINE__, __FILE__, false, false ); verify_analyze< failure >( __LINE__, __FILE__, true, false ); + // clang-format off { - struct tst : star< tst > - { - }; + struct tst : star< tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : plus< tst > - { - }; + struct tst : plus< tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : seq< eof, at< digit >, tst > - { - }; + struct tst : seq< eof, at< digit >, tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); // This is a false positive. } { - struct tst : sor< digit, seq< at< digit >, tst > > - { - }; + struct tst : sor< digit, seq< at< digit >, tst > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); // This is a false positive. } { - struct tst : sor< digit, seq< opt< digit >, tst > > - { - }; + struct tst : sor< digit, seq< opt< digit >, tst > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : sor< digit, tst > - { - }; + struct tst : sor< digit, tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : at< any > - { - }; + struct tst : at< any > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : at< tst > - { - }; + struct tst : at< tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : at< any, tst > - { - }; + struct tst : at< any, tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : not_at< any > - { - }; + struct tst : not_at< any > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : opt< tst > - { - }; + struct tst : opt< tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : opt< any, tst > - { - }; + struct tst : opt< any, tst > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct rec : sor< seq< rec, alpha >, alpha > - { - }; + struct rec : sor< seq< rec, alpha >, alpha > {}; verify_analyze< rec >( __LINE__, __FILE__, true, true ); } { struct bar; - struct foo : seq< digit, bar > - { - }; - struct bar : plus< foo > - { - }; + struct foo : seq< digit, bar > {}; + struct bar : plus< foo > {}; verify_analyze< seq< any, bar > >( __LINE__, __FILE__, true, false ); } { struct bar; - struct foo : seq< bar, digit > - { - }; - struct bar : plus< foo > - { - }; + struct foo : seq< bar, digit > {}; + struct bar : plus< foo > {}; verify_analyze< seq< bar, any > >( __LINE__, __FILE__, true, true ); } { struct bar; - struct foo : sor< digit, bar > - { - }; - struct bar : plus< foo > - { - }; + struct foo : sor< digit, bar > {}; + struct bar : plus< foo > {}; verify_analyze< bar >( __LINE__, __FILE__, false, true ); verify_analyze< foo >( __LINE__, __FILE__, false, true ); verify_analyze< sor< any, bar > >( __LINE__, __FILE__, false, true ); @@ -137,169 +93,110 @@ namespace TAO_PEGTL_NAMESPACE // Simplified version, equivalent regarding consumption of input: struct var; struct fun; - struct exp : sor< var, fun, seq< any, exp, any > > - { - }; - struct fun : seq< exp, any > - { - }; - struct var : sor< any, seq< exp, any, exp >, seq< exp, any > > - { - }; + struct exp : sor< var, fun, seq< any, exp, any > > {}; + struct fun : seq< exp, any > {}; + struct var : sor< any, seq< exp, any, exp >, seq< exp, any > > {}; verify_analyze< exp >( __LINE__, __FILE__, true, true ); verify_analyze< fun >( __LINE__, __FILE__, true, true ); verify_analyze< var >( __LINE__, __FILE__, true, true ); } { - struct exp : sor< exp, seq< any, exp > > - { - }; + struct exp : sor< exp, seq< any, exp > > {}; verify_analyze< exp >( __LINE__, __FILE__, false, true ); } { - struct tst : until< any > - { - }; + struct tst : until< any > {}; verify_analyze< tst >( __LINE__, __FILE__, true, false ); } { - struct tst : until< star< any > > - { - }; + struct tst : until< star< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : until< any, star< any > > - { - }; + struct tst : until< any, star< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, true, true ); } { - struct tst : until< star< any >, star< any > > - { - }; + struct tst : until< star< any >, star< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : until< star< any >, star< any > > - { - }; - verify_analyze< any_seq< tst > >( __LINE__, __FILE__, true, true ); - } - { - struct tst : until< any, any > - { - }; + struct tst : until< any, any > {}; verify_analyze< tst >( __LINE__, __FILE__, true, false ); } { - struct tst : until< star< any >, any > - { - }; + struct tst : until< star< any >, any > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : plus< plus< any > > - { - }; + struct tst : plus< plus< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, true, false ); } { - struct tst : star< star< any > > - { - }; + struct tst : star< star< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : plus< star< any > > - { - }; + struct tst : plus< star< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : plus< opt< any > > - { - }; + struct tst : plus< opt< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : star< opt< any > > - { - }; + struct tst : star< opt< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : star< plus< opt< any > > > - { - }; + struct tst : star< plus< opt< any > > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : list< any, any > - { - }; + struct tst : list< any, any > {}; verify_analyze< tst >( __LINE__, __FILE__, true, false ); } { - struct tst : list< star< any >, any > - { - }; + struct tst : list< star< any >, any > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : list< any, opt< any > > - { - }; + struct tst : list< any, opt< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, true, false ); } { - struct tst : list< star< any >, opt< any > > - { - }; + struct tst : list< star< any >, opt< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : list_must< any, any > - { - }; + struct tst : list_must< any, any > {}; verify_analyze< tst >( __LINE__, __FILE__, true, false ); } { - struct tst : list_must< star< any >, any > - { - }; + struct tst : list_must< star< any >, any > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : list_must< any, opt< any > > - { - }; + struct tst : list_must< any, opt< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, true, false ); } { - struct tst : list_must< star< any >, opt< any > > - { - }; + struct tst : list_must< star< any >, opt< any > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : plus< pad_opt< alpha, digit > > - { - }; + struct tst : plus< pad_opt< alpha, digit > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } { - struct tst : rep< 42, opt< alpha > > - { - }; + struct tst : rep< 42, opt< alpha > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, false ); } { - struct tst : rep_min< 42, opt< alpha > > - { - }; + struct tst : rep_min< 42, opt< alpha > > {}; verify_analyze< tst >( __LINE__, __FILE__, false, true ); } + // clang-format on } } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/src/test/pegtl/contrib_http.cpp b/packages/PEGTL/src/test/pegtl/contrib_http.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4f74cd5adc0e3c5a2cdceccd8351e38a0ca0272 --- /dev/null +++ b/packages/PEGTL/src/test/pegtl/contrib_http.cpp @@ -0,0 +1,94 @@ +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#include "test.hpp" +#include "verify_analyze.hpp" + +#include <tao/pegtl/contrib/http.hpp> + +namespace TAO_PEGTL_NAMESPACE +{ + void test_header() + { + // TODO. + } + + template< typename Rule > + struct chunked_action + : nothing< Rule > + {}; + + template<> + struct chunked_action< http::chunk_ext > + { + static void apply0( std::string& s ) + { + s += 'a'; + } + }; + + template<> + struct chunked_action< http::chunk_data > + { + static void apply0( std::string& s ) + { + s += 'b'; + } + }; + + void test_chunked() + { + using GRAMMAR = must< http::chunked_body, eof >; + + verify_analyze< GRAMMAR >( __LINE__, __FILE__, true, false ); + { + string_input in( "0\r\n\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_ASSERT( parse< GRAMMAR >( in ) ); + } + { + std::string dummy; + string_input in( "0\r\n\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_ASSERT( parse< GRAMMAR >( in, dummy ) ); + } + { + std::string state; + string_input in( "0\r\n\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_ASSERT( parse< GRAMMAR, chunked_action >( in, state ) ); + TAO_PEGTL_TEST_ASSERT( state == "a" ); + } + { + std::string state; + string_input in( "\r\n\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_THROWS( parse< GRAMMAR, chunked_action >( in, state ) ); + } + { + std::string state; + string_input in( "1\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_THROWS( parse< GRAMMAR, chunked_action >( in, state ) ); + } + { + string_input in( "01\r\nX\r\n1a\r\nabcdefghijklmnopqrstuvwxyz\r\n0\r\n\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_ASSERT( parse< GRAMMAR >( in ) ); + } + { + std::string dummy; + string_input in( "01\r\nX\r\n1a\r\nabcdefghijklmnopqrstuvwxyz\r\n0\r\n\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_ASSERT( parse< GRAMMAR >( in, dummy ) ); + } + { + std::string state; + string_input in( "01\r\nX\r\n1A\r\nabcdefghijklmnopqrstuvwxyz\r\n0\r\n\r\n", __FUNCTION__ ); + TAO_PEGTL_TEST_ASSERT( parse< GRAMMAR, chunked_action >( in, state ) ); + TAO_PEGTL_TEST_ASSERT( state == "ababa" ); + } + } + + void unit_test() + { + test_header(); + test_chunked(); + } + +} // namespace TAO_PEGTL_NAMESPACE + +#include "main.hpp" diff --git a/packages/PEGTL/src/test/pegtl/contrib_if_then.cpp b/packages/PEGTL/src/test/pegtl/contrib_if_then.cpp index 36199ecf45a2cff08c024803c42c81d0b3989076..b81c7840c89ad7c490be8a56ccc8788067898742 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_if_then.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_if_then.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/contrib_integer.cpp b/packages/PEGTL/src/test/pegtl/contrib_integer.cpp index a6f3d9a52e698dc1a6002a5da1e02e000a48fc81..9290f670de8575ba55f0feacaeaaee80912ac2c2 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_integer.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_integer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <limits> @@ -6,6 +6,9 @@ #include "test.hpp" +#include "verify_analyze.hpp" +#include "verify_rule.hpp" + #include <tao/pegtl/contrib/integer.hpp> namespace TAO_PEGTL_NAMESPACE @@ -18,25 +21,40 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule > struct int_action + : nothing< Rule > {}; template<> - struct int_action< integer::signed_rule > - : integer::signed_action + struct int_action< signed_rule > + : signed_action {}; template<> - struct int_action< integer::unsigned_rule > - : integer::unsigned_action + struct int_action< unsigned_rule > + : unsigned_action {}; template< typename S > void test_signed( const std::string& i, const S s ) { - int_state< S > st; - memory_input in( i, __FUNCTION__ ); - parse< must< integer::signed_rule, eof >, int_action >( in, st ); - TAO_PEGTL_TEST_ASSERT( st.converted == s ); + { + S st = -123; + memory_input in( i, __FUNCTION__ ); + parse< must< signed_rule, eof >, int_action >( in, st ); + TAO_PEGTL_TEST_ASSERT( st == s ); + } + { + int_state< S > st; + memory_input in( i, __FUNCTION__ ); + parse< must< signed_rule, eof >, int_action >( in, st ); + TAO_PEGTL_TEST_ASSERT( st.converted == s ); + } + { + S st = -123; + memory_input in( i, __FUNCTION__ ); + parse< must< signed_rule_with_action, eof > >( in, st ); + TAO_PEGTL_TEST_ASSERT( st == s ); + } } template< typename S > @@ -44,7 +62,7 @@ namespace TAO_PEGTL_NAMESPACE { int_state< S > st; memory_input in( i, __FUNCTION__ ); - TAO_PEGTL_TEST_THROWS( parse< must< integer::signed_rule, eof >, int_action >( in, st ) ); + TAO_PEGTL_TEST_THROWS( parse< must< signed_rule, eof >, int_action >( in, st ) ); } template< typename S > @@ -61,39 +79,61 @@ namespace TAO_PEGTL_NAMESPACE int_state< S > st; const auto i = lexical_cast( s ); memory_input in( i, __FUNCTION__ ); - parse< must< integer::signed_rule, eof >, int_action >( in, st ); + parse< must< signed_rule, eof >, int_action >( in, st ); TAO_PEGTL_TEST_ASSERT( st.converted == s ); } template< typename S > void test_unsigned( const std::string& i, const S s ) { - int_state< S > st; - memory_input in( i, __FUNCTION__ ); - parse< must< integer::unsigned_rule, eof >, int_action >( in, st ); - TAO_PEGTL_TEST_ASSERT( st.converted == s ); + { + S st = 123; + memory_input in( i, __FUNCTION__ ); + parse< must< unsigned_rule, eof >, int_action >( in, st ); + TAO_PEGTL_TEST_ASSERT( st == s ); + } + { + int_state< S > st; + memory_input in( i, __FUNCTION__ ); + parse< must< unsigned_rule, eof >, int_action >( in, st ); + TAO_PEGTL_TEST_ASSERT( st.converted == s ); + } + { + S st = 123; + memory_input in( i, __FUNCTION__ ); + parse< must< unsigned_rule_with_action, eof > >( in, st ); + TAO_PEGTL_TEST_ASSERT( st == s ); + } } template< typename S > void test_unsigned( const std::string& i ) { - int_state< S > st; + S st = 123; memory_input in( i, __FUNCTION__ ); - TAO_PEGTL_TEST_THROWS( parse< must< integer::unsigned_rule, eof >, int_action >( in, st ) ); + TAO_PEGTL_TEST_THROWS( parse< must< unsigned_rule, eof >, int_action >( in, st ) ); } template< typename S > void test_unsigned( const S s ) { - int_state< S > st; + S st = 123; const auto i = lexical_cast( s ); memory_input in( i, __FUNCTION__ ); - parse< must< integer::unsigned_rule, eof >, int_action >( in, st ); - TAO_PEGTL_TEST_ASSERT( st.converted == s ); + parse< must< unsigned_rule, eof >, int_action >( in, st ); + TAO_PEGTL_TEST_ASSERT( st == s ); } + template< auto M > + using max_seq_rule = seq< one< 'a' >, maximum_rule< std::uint64_t, M >, one< 'b' >, eof >; + void unit_test() { + test_signed< signed char >( "" ); + test_signed< signed char >( "-" ); + test_signed< signed char >( "+" ); + test_signed< signed char >( "a" ); + test_signed< signed char >( "--0" ); test_signed< signed char >( "++0" ); test_signed< signed char >( "-+0" ); @@ -101,32 +141,44 @@ namespace TAO_PEGTL_NAMESPACE test_signed< signed char >( "0", 0 ); test_signed< signed char >( "+0", 0 ); test_signed< signed char >( "-0", 0 ); - test_signed< signed char >( "000", 0 ); - test_signed< signed char >( "+000", 0 ); - test_signed< signed char >( "-000", 0 ); + test_signed< signed char >( "000" ); + + test_signed< signed char >( "+000" ); + test_signed< signed char >( "-000" ); test_signed< signed char >( "127", 127 ); + test_signed< signed char >( "0127" ); test_signed< signed char >( "-1", -1 ); - test_signed< signed char >( "-001", -1 ); + test_signed< signed char >( "-01" ); + test_signed< signed char >( "-001" ); test_signed< signed char >( "-127", -127 ); test_signed< signed char >( "-128", -128 ); test_signed< signed char >( "128" ); test_signed< signed char >( "-129" ); + test_signed< signed char >( "0128" ); test_signed< signed char >( "00128" ); + test_signed< signed char >( "-0129" ); test_signed< signed char >( "-00129" ); + test_unsigned< unsigned char >( "" ); + test_unsigned< unsigned char >( "-" ); + test_unsigned< unsigned char >( "+" ); + test_unsigned< unsigned char >( "a" ); + test_unsigned< unsigned char >( "-0" ); test_unsigned< unsigned char >( "+1" ); test_unsigned< unsigned char >( "0", 0 ); - test_unsigned< unsigned char >( "000", 0 ); + test_unsigned< unsigned char >( "000" ); test_unsigned< unsigned char >( "0", 0 ); test_unsigned< unsigned char >( "255", 255 ); - test_unsigned< unsigned char >( "000255", 255 ); + test_unsigned< unsigned char >( "0255" ); + test_unsigned< unsigned char >( "000255" ); test_unsigned< unsigned char >( "256" ); + test_unsigned< unsigned char >( "0256" ); test_unsigned< unsigned char >( "000256" ); test_signed< signed long long >( "0", 0 ); @@ -135,6 +187,82 @@ namespace TAO_PEGTL_NAMESPACE test_unsigned< unsigned long long >( "0", 0 ); test_unsigned< unsigned long long >( ( std::numeric_limits< unsigned long long >::max )() ); + + verify_rule< max_seq_rule< 0 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 0 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 0 > >( __LINE__, __FILE__, "a1b", result_type::global_failure ); + verify_rule< max_seq_rule< 0 > >( __LINE__, __FILE__, "a9b", result_type::global_failure ); + verify_rule< max_seq_rule< 0 > >( __LINE__, __FILE__, "a11b", result_type::global_failure ); + + verify_rule< max_seq_rule< 1 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 1 > >( __LINE__, __FILE__, "a1b", result_type::success ); + verify_rule< max_seq_rule< 1 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 1 > >( __LINE__, __FILE__, "a2b", result_type::global_failure ); + verify_rule< max_seq_rule< 1 > >( __LINE__, __FILE__, "a9b", result_type::global_failure ); + verify_rule< max_seq_rule< 1 > >( __LINE__, __FILE__, "a11b", result_type::global_failure ); + + verify_rule< max_seq_rule< 2 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 2 > >( __LINE__, __FILE__, "a1b", result_type::success ); + verify_rule< max_seq_rule< 2 > >( __LINE__, __FILE__, "a2b", result_type::success ); + verify_rule< max_seq_rule< 2 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 2 > >( __LINE__, __FILE__, "a3b", result_type::global_failure ); + verify_rule< max_seq_rule< 2 > >( __LINE__, __FILE__, "a9b", result_type::global_failure ); + verify_rule< max_seq_rule< 2 > >( __LINE__, __FILE__, "a11b", result_type::global_failure ); + + verify_rule< max_seq_rule< 3 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 3 > >( __LINE__, __FILE__, "a3b", result_type::success ); + verify_rule< max_seq_rule< 3 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 3 > >( __LINE__, __FILE__, "a4b", result_type::global_failure ); + verify_rule< max_seq_rule< 3 > >( __LINE__, __FILE__, "a11b", result_type::global_failure ); + + verify_rule< max_seq_rule< 4 > >( __LINE__, __FILE__, "a5b", result_type::global_failure ); + verify_rule< max_seq_rule< 4 > >( __LINE__, __FILE__, "a11b", result_type::global_failure ); + + verify_rule< max_seq_rule< 9 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 9 > >( __LINE__, __FILE__, "a9b", result_type::success ); + verify_rule< max_seq_rule< 9 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 9 > >( __LINE__, __FILE__, "a10b", result_type::global_failure ); + verify_rule< max_seq_rule< 9 > >( __LINE__, __FILE__, "a11b", result_type::global_failure ); + + verify_rule< max_seq_rule< 10 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 10 > >( __LINE__, __FILE__, "a9b", result_type::success ); + verify_rule< max_seq_rule< 10 > >( __LINE__, __FILE__, "a10b", result_type::success ); + verify_rule< max_seq_rule< 10 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 10 > >( __LINE__, __FILE__, "a11b", result_type::global_failure ); + verify_rule< max_seq_rule< 10 > >( __LINE__, __FILE__, "a19b", result_type::global_failure ); + + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "a9b", result_type::success ); + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "a10b", result_type::success ); + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "a11b", result_type::success ); + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "a12b", result_type::global_failure ); + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "a13b", result_type::global_failure ); + verify_rule< max_seq_rule< 11 > >( __LINE__, __FILE__, "a111b", result_type::global_failure ); + + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a0b", result_type::success ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a1b", result_type::success ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a9b", result_type::success ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a10b", result_type::success ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a11b", result_type::success ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a12b", result_type::success ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "ab", result_type::local_failure ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a13b", result_type::global_failure ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a19b", result_type::global_failure ); + verify_rule< max_seq_rule< 12 > >( __LINE__, __FILE__, "a111b", result_type::global_failure ); + + verify_rule< max_seq_rule< 18446744073709551614ULL > >( __LINE__, __FILE__, "a18446744073709551614b", result_type::success ); + verify_rule< max_seq_rule< 18446744073709551614ULL > >( __LINE__, __FILE__, "a18446744073709551615b", result_type::global_failure ); + + verify_rule< max_seq_rule< 18446744073709551615ULL > >( __LINE__, __FILE__, "a18446744073709551615b", result_type::success ); + verify_rule< max_seq_rule< 18446744073709551615ULL > >( __LINE__, __FILE__, "a18446744073709551616b", result_type::global_failure ); + verify_rule< max_seq_rule< 18446744073709551615ULL > >( __LINE__, __FILE__, "a98446744073709551614b", result_type::global_failure ); + + verify_analyze< unsigned_rule >( __LINE__, __FILE__, true, false ); + verify_analyze< unsigned_rule_with_action >( __LINE__, __FILE__, true, false ); + + verify_analyze< signed_rule >( __LINE__, __FILE__, true, false ); + verify_analyze< signed_rule_with_action >( __LINE__, __FILE__, true, false ); } } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/src/test/pegtl/contrib_json.cpp b/packages/PEGTL/src/test/pegtl/contrib_json.cpp index d438385aea924cf4a8f3e8b1cb17d079d44aaa6b..67abd1d1d9083abeb67e8d68ed0a5080fa6312b3 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_json.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_json.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -6,7 +6,6 @@ #include "verify_fail.hpp" #include "verify_rule.hpp" -#include <tao/pegtl/analyze.hpp> #include <tao/pegtl/contrib/json.hpp> namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp b/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp index 2df7a9b301a0abdfa303480549819b6d0b805c9c..521a8140cdb8d7eaac1c78d370b38ee9cbbbf8f9 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -18,8 +18,7 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule > struct selector : parse_tree::selector< Rule, parse_tree::store_content::on< A, B, C, D > > - { - }; + {}; void unit_test() { @@ -31,11 +30,7 @@ namespace TAO_PEGTL_NAMESPACE const auto& d = r->children.front(); TAO_PEGTL_TEST_ASSERT( !d->is_root() ); - TAO_PEGTL_TEST_ASSERT( d->id == typeid( D ) ); - TAO_PEGTL_TEST_ASSERT( d->is< D >() ); -#if !defined( _MSC_VER ) - TAO_PEGTL_TEST_ASSERT( d->name() == "tao::pegtl::D" ); -#endif + TAO_PEGTL_TEST_ASSERT( d->is_type< D >() ); TAO_PEGTL_TEST_ASSERT( d->has_content() ); TAO_PEGTL_TEST_ASSERT( d->begin().byte == 0 ); @@ -43,8 +38,8 @@ namespace TAO_PEGTL_NAMESPACE TAO_PEGTL_TEST_ASSERT( d->string_view() == "ac" ); TAO_PEGTL_TEST_ASSERT( d->children.size() == 2 ); - TAO_PEGTL_TEST_ASSERT( d->children.front()->is< A >() ); - TAO_PEGTL_TEST_ASSERT( d->children.back()->is< C >() ); + TAO_PEGTL_TEST_ASSERT( d->children.front()->is_type< A >() ); + TAO_PEGTL_TEST_ASSERT( d->children.back()->is_type< C >() ); memory_input in2( "x", "input" ); const auto r2 = parse_tree::parse< D, selector >( in2 ); diff --git a/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp b/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp index f4d82a1d747880960cc27e3c640e4e592401ea45..b8ac7a168bbedd7c66f3020e04e4b35793febec5 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp @@ -1,9 +1,9 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" -#include <tao/pegtl/contrib/tracer.hpp> +#include <tao/pegtl/contrib/trace.hpp> namespace TAO_PEGTL_NAMESPACE { @@ -13,7 +13,7 @@ namespace TAO_PEGTL_NAMESPACE // how to run a tracer on a *part* of the grammar: template< typename > struct partial_action {}; - template<> struct partial_action< inner > : change_control< tracer > {}; + template<> struct partial_action< inner > : change_control< trace_control > {}; // clang-format on void unit_test() diff --git a/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp b/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp index 6c41cfca344c520caad90720f106b4e35d1fe9e7..95d2737e72d37b5bea2ffce010c4e3e822503b72 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp @@ -1,14 +1,15 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" +#include "verify_analyze.hpp" #include "verify_fail.hpp" #include <tao/pegtl/contrib/raw_string.hpp> namespace TAO_PEGTL_NAMESPACE { - std::string content; // NOLINT + std::string content; using rstring = raw_string< '[', '=', ']' >; using qstring = raw_string< '[', '=', ']', alpha, digit >; @@ -20,8 +21,8 @@ namespace TAO_PEGTL_NAMESPACE template<> struct raction< rstring::content > { - template< typename Input, typename... States > - static void apply( const Input& in, const States&... /*unused*/ ) + template< typename ActionInput, typename... States > + static void apply( const ActionInput& in, const States&... /*unused*/ ) { content.assign( in.begin(), in.end() ); } @@ -34,8 +35,8 @@ namespace TAO_PEGTL_NAMESPACE template<> struct qaction< qstring::content > { - template< typename Input, typename... States > - static void apply( const Input& in, const States&... /*unused*/ ) + template< typename ActionInput, typename... States > + static void apply( const ActionInput& in, const States&... /*unused*/ ) { content.assign( in.begin(), in.end() ); } @@ -43,16 +44,14 @@ namespace TAO_PEGTL_NAMESPACE struct rgrammar : must< rstring, eof > - { - }; + {}; struct qgrammar : must< qstring, eof > - { - }; + {}; template< typename Rule, template< typename > class Action, unsigned M, unsigned N > - void verify_data( const std::size_t line, const char* file, const char ( &m )[ M ], const char ( &n )[ N ] ) // NOLINT + void verify_data( const std::size_t line, const char* file, const char ( &m )[ M ], const char ( &n )[ N ] ) { content.clear(); memory_input in( m, m + M - 1, file, 0, line, 0 ); @@ -70,6 +69,11 @@ namespace TAO_PEGTL_NAMESPACE void unit_test() { + verify_analyze< rstring >( __LINE__, __FILE__, true, false ); + verify_analyze< qstring >( __LINE__, __FILE__, true, false ); + + verify_analyze< raw_string< 'a', 'b', 'c', star< star< any > > > >( __LINE__, __FILE__, true, true ); + verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[]]", "" ); verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[foo]]", "foo" ); verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[foo]===]", "foo" ); diff --git a/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp b/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp index ebfb08680611f4a86eec2685329d0abe48db7251..b190a0cca7737bf17dd160fdcff57b9f50a491df 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/contrib_to_string.cpp b/packages/PEGTL/src/test/pegtl/contrib_to_string.cpp index 55f9d2749d28bcd704b20459e38c8d4dcaf1c2e2..f2c4b175129d340f666b8d292d08858ad1623395 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_to_string.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_to_string.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp b/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp index 1d8ac50107ee9ba3736ea4f80e96ed7fd6274dc7..074c701f71d2eed0486754949762ede23348fd3b 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp @@ -1,9 +1,9 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" -#include <tao/pegtl/contrib/tracer.hpp> +#include <tao/pegtl/contrib/trace.hpp> namespace TAO_PEGTL_NAMESPACE { @@ -11,14 +11,14 @@ namespace TAO_PEGTL_NAMESPACE using GRAMMAR2 = seq< one< 'a' >, any, any, any, any, one< 'b' >, eof >; template< typename Rule > - struct tracer_action + struct trace_action {}; unsigned a0 = 0; unsigned a = 0; template<> - struct tracer_action< one< 'a' > > + struct trace_action< one< 'a' > > { template< typename... Ts > static void apply0( Ts&&... /*unused*/ ) @@ -28,7 +28,7 @@ namespace TAO_PEGTL_NAMESPACE }; template<> - struct tracer_action< GRAMMAR > + struct trace_action< GRAMMAR > { template< typename... Ts > static void apply( Ts&&... /*unused*/ ) @@ -41,14 +41,14 @@ namespace TAO_PEGTL_NAMESPACE { { memory_input in( "ab", "trace test please ignore" ); - const auto result = parse< GRAMMAR, nothing, tracer >( in ); + const auto result = parse< GRAMMAR, nothing, trace_control >( in ); TAO_PEGTL_TEST_ASSERT( result ); TAO_PEGTL_TEST_ASSERT( a0 == 0 ); TAO_PEGTL_TEST_ASSERT( a == 0 ); } { memory_input in( "ab", "trace test please ignore" ); - const auto result = parse< GRAMMAR, tracer_action, tracer >( in ); + const auto result = parse< GRAMMAR, trace_action, trace_control >( in ); TAO_PEGTL_TEST_ASSERT( result ); TAO_PEGTL_TEST_ASSERT( a0 == 1 ); TAO_PEGTL_TEST_ASSERT( a == 1 ); @@ -56,7 +56,7 @@ namespace TAO_PEGTL_NAMESPACE { trace_state ts; memory_input in( "ab", "trace test please ignore" ); - const auto result = parse< GRAMMAR, nothing, tracer >( in, ts ); + const auto result = parse< GRAMMAR, nothing, trace_control >( in, ts ); TAO_PEGTL_TEST_ASSERT( result ); TAO_PEGTL_TEST_ASSERT( a0 == 1 ); TAO_PEGTL_TEST_ASSERT( a == 1 ); @@ -64,7 +64,7 @@ namespace TAO_PEGTL_NAMESPACE { trace_state ts; memory_input in( "ab", "trace test please ignore" ); - const auto result = parse< GRAMMAR, tracer_action, tracer >( in, ts ); + const auto result = parse< GRAMMAR, trace_action, trace_control >( in, ts ); TAO_PEGTL_TEST_ASSERT( result ); TAO_PEGTL_TEST_ASSERT( a0 == 2 ); TAO_PEGTL_TEST_ASSERT( a == 2 ); @@ -72,7 +72,7 @@ namespace TAO_PEGTL_NAMESPACE { trace_state ts; memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" ); - const auto result = parse< GRAMMAR2, nothing, tracer >( in, ts ); + const auto result = parse< GRAMMAR2, nothing, trace_control >( in, ts ); TAO_PEGTL_TEST_ASSERT( result ); TAO_PEGTL_TEST_ASSERT( a0 == 2 ); TAO_PEGTL_TEST_ASSERT( a == 2 ); @@ -80,7 +80,7 @@ namespace TAO_PEGTL_NAMESPACE { trace_state ts; memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" ); - const auto result = parse< GRAMMAR2, tracer_action, tracer >( in, ts ); + const auto result = parse< GRAMMAR2, trace_action, trace_control >( in, ts ); TAO_PEGTL_TEST_ASSERT( result ); } } diff --git a/packages/PEGTL/src/test/pegtl/contrib_unescape.cpp b/packages/PEGTL/src/test/pegtl/contrib_unescape.cpp index f31754192121d152193cc0e69f24b2f79c062059..8bf92f2aa7e990d6a604f46ed92008abec386242 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_unescape.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_unescape.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -29,13 +29,13 @@ namespace TAO_PEGTL_NAMESPACE // clang-format on template< unsigned M, unsigned N > - void verify_data( const char ( &m )[ M ], const char ( &n )[ N ] ) // NOLINT + void verify_data( const char ( &m )[ M ], const char ( &n )[ N ] ) { std::string s; memory_input in( m, M - 1, __FUNCTION__ ); parse< unstring, unaction >( in, s ); if( s != std::string( n, N - 1 ) ) { - throw std::runtime_error( "test failed!" ); // NOLINT + throw std::runtime_error( "test failed!" ); } } diff --git a/packages/PEGTL/src/test/pegtl/contrib_uri.cpp b/packages/PEGTL/src/test/pegtl/contrib_uri.cpp index e9317f8cef5b3f2b0a6e3984aa2f745601d49fbb..a35ce90992ce71826711abb2d3131b629ec110a8 100644 --- a/packages/PEGTL/src/test/pegtl/contrib_uri.cpp +++ b/packages/PEGTL/src/test/pegtl/contrib_uri.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/data_cstring.cpp b/packages/PEGTL/src/test/pegtl/data_cstring.cpp index 9828c35f5c16b74da882b5416f2fa4682c04c729..bf8dd4a8036038c438b84831b4b493e039cc0b14 100644 --- a/packages/PEGTL/src/test/pegtl/data_cstring.cpp +++ b/packages/PEGTL/src/test/pegtl/data_cstring.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -16,9 +16,9 @@ namespace TAO_PEGTL_NAMESPACE return parse< Rule, Action, Control >( in ); } - struct test_grammar : seq< string< 'a', 'b', 'c', 'd', 'e', 'f' >, not_at< any >, eof > - { - }; + struct test_grammar + : seq< string< 'a', 'b', 'c', 'd', 'e', 'f' >, not_at< any >, eof > + {}; void unit_test() { diff --git a/packages/PEGTL/src/test/pegtl/demangle.cpp b/packages/PEGTL/src/test/pegtl/demangle.cpp index a83296d59454670e22df0fc4665a238134e7972f..ee76d1db381833e12ee8df9d72c3792c0c18eb21 100644 --- a/packages/PEGTL/src/test/pegtl/demangle.cpp +++ b/packages/PEGTL/src/test/pegtl/demangle.cpp @@ -1,33 +1,34 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" -#include <tao/pegtl/internal/demangle_sanitise.hpp> +#include <tao/pegtl/internal/demangle.hpp> namespace TAO_PEGTL_NAMESPACE { - void test_chars( std::string a, const std::string& b ) + template< typename T > + void test( const std::string& s ) { - internal::demangle_sanitise_chars( a ); - TAO_PEGTL_TEST_ASSERT( a == b ); + TAO_PEGTL_TEST_ASSERT( internal::demangle< T >() == s ); } void unit_test() { - const std::string s = "something that can't be demangled"; - const std::string a = internal::demangle( s.c_str() ); - TAO_PEGTL_TEST_ASSERT( a == s ); - const std::string b = internal::demangle< std::string >(); - (void)b; // Not standardised. - - test_chars( "zzz(char)1xxx", "zzz1xxx" ); - test_chars( "zzz(char)32xxx", "zzz' 'xxx" ); - test_chars( "zzz(char)48xxx", "zzz'0'xxx" ); - test_chars( "zzz(char)39xxx", "zzz'\\''xxx" ); - test_chars( "zzz(char)92xxx", "zzz'\\\\'xxx" ); - test_chars( "frobnicate<> (char)1 (char)32 (char)48 ***", "frobnicate<> 1 ' ' '0' ***" ); - test_chars( "tao::pegtl::internal::until<tao::pegtl::at<tao::pegtl::ascii::one<(char)34> >", "tao::pegtl::internal::until<tao::pegtl::at<tao::pegtl::ascii::one<'\"'> >" ); +#if !defined( __clang__ ) && defined( __GNUC__ ) && ( __GNUC__ == 9 ) && ( __GNUC_MINOR__ <= 2 ) + // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91155 + test< int >( "i" ); + test< double >( "d" ); + test< seq< bytes< 42 >, eof > >( "N3tao5pegtl3seqIJNS0_5bytesILj42EEENS0_3eofEEEE" ); +#elif defined( _MSC_VER ) + test< int >( "int" ); + test< double >( "double" ); + test< seq< bytes< 42 >, eof > >( "struct tao::pegtl::seq<struct tao::pegtl::bytes<42>,struct tao::pegtl::eof>" ); +#else + test< int >( "int" ); + test< double >( "double" ); + test< seq< bytes< 42 >, eof > >( "tao::pegtl::seq<tao::pegtl::bytes<42>, tao::pegtl::eof>" ); +#endif } } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/src/test/pegtl/discard_input.cpp b/packages/PEGTL/src/test/pegtl/discard_input.cpp index b693db5064b94d92c7d8148672387e6db5d34f8e..3033d365db8c378dea636b55b59b7f5365eb9518 100644 --- a/packages/PEGTL/src/test/pegtl/discard_input.cpp +++ b/packages/PEGTL/src/test/pegtl/discard_input.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <string> diff --git a/packages/PEGTL/src/test/pegtl/error_message.cpp b/packages/PEGTL/src/test/pegtl/error_message.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05870afbaf6e2ff595f9eefec1e27fdd6f8543c1 --- /dev/null +++ b/packages/PEGTL/src/test/pegtl/error_message.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#include "test.hpp" + +namespace test1 +{ + using namespace TAO_PEGTL_NAMESPACE; + + // clang-format off + struct a : one< 'a' > {}; + struct b : one< 'b' > {}; + struct grammar : sor< a, b > {}; + + template< typename > inline constexpr const char* error_message = nullptr; + template<> inline constexpr auto error_message< test1::a > = "test123"; + + struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; }; + template< typename Rule > using control = must_if< error >::control< Rule >; + // clang-format on + +} // namespace test1 + +namespace TAO_PEGTL_NAMESPACE +{ + void unit_test() + { + try { + parse< test1::grammar, nothing, test1::control >( memory_input( "b", __FUNCTION__ ) ); + TAO_PEGTL_TEST_ASSERT( false ); + } + catch( const parse_error& e ) { + if( e.what() != std::string( "test123" ) ) { + throw; + } + } + } + +} // namespace TAO_PEGTL_NAMESPACE + +#include "main.hpp" diff --git a/packages/PEGTL/src/test/pegtl/file_cstream.cpp b/packages/PEGTL/src/test/pegtl/file_cstream.cpp index 0560a33e9a8b3ad7b4de3dc13f2f970e38dd53a2..85d13f443da76f502c1515f5579c570ca193f4e2 100644 --- a/packages/PEGTL/src/test/pegtl/file_cstream.cpp +++ b/packages/PEGTL/src/test/pegtl/file_cstream.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <clocale> @@ -8,26 +8,26 @@ namespace TAO_PEGTL_NAMESPACE { - struct file_content : seq< TAO_PEGTL_STRING( "dummy content" ), eol, discard > - { - }; + struct file_content + : seq< TAO_PEGTL_STRING( "dummy content" ), eol, discard > + {}; - struct file_grammar : seq< rep_min_max< 11, 11, file_content >, eof > - { - }; + struct file_grammar + : seq< rep_min_max< 11, 11, file_content >, eof > + {}; void unit_test() { const char* const filename = "src/test/pegtl/file_data.txt"; #if defined( _MSC_VER ) std::FILE* stream; - ::fopen_s( &stream, filename, "rb" ); // NOLINT + ::fopen_s( &stream, filename, "rb" ); #else - std::FILE* stream = std::fopen( filename, "rb" ); // NOLINT + std::FILE* stream = std::fopen( filename, "rb" ); #endif TAO_PEGTL_TEST_ASSERT( stream != nullptr ); TAO_PEGTL_TEST_ASSERT( parse< file_grammar >( cstream_input( stream, 16, filename ) ) ); - std::fclose( stream ); // NOLINT(cppcoreguidelines-owning-memory) + std::fclose( stream ); } } // namespace TAO_PEGTL_NAMESPACE diff --git a/packages/PEGTL/src/test/pegtl/file_file.cpp b/packages/PEGTL/src/test/pegtl/file_file.cpp index 4e7da95350819f0509945d740430d6c178a695e6..c7a4a904161a549ee2e530ad17761231cc2ac1bf 100644 --- a/packages/PEGTL/src/test/pegtl/file_file.cpp +++ b/packages/PEGTL/src/test/pegtl/file_file.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/file_istream.cpp b/packages/PEGTL/src/test/pegtl/file_istream.cpp index b4862f25f62c85ed6aa2f3d30fd8705dab172c1e..9b76d071e728dad6521f9b68467aa963492fc8c1 100644 --- a/packages/PEGTL/src/test/pegtl/file_istream.cpp +++ b/packages/PEGTL/src/test/pegtl/file_istream.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <cerrno> @@ -8,13 +8,13 @@ namespace TAO_PEGTL_NAMESPACE { - struct file_content : seq< TAO_PEGTL_STRING( "dummy content" ), eol, discard > - { - }; + struct file_content + : seq< TAO_PEGTL_STRING( "dummy content" ), eol, discard > + {}; - struct file_grammar : seq< rep_min_max< 11, 11, file_content >, eof > - { - }; + struct file_grammar + : seq< rep_min_max< 11, 11, file_content >, eof > + {}; void unit_test() { diff --git a/packages/PEGTL/src/test/pegtl/file_mmap.cpp b/packages/PEGTL/src/test/pegtl/file_mmap.cpp index c7297c1874444613468d075cb646ca34f644cc84..478b3b1f0181452324829c63011734b753da7e15 100644 --- a/packages/PEGTL/src/test/pegtl/file_mmap.cpp +++ b/packages/PEGTL/src/test/pegtl/file_mmap.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ // this include gives us _POSIX_MAPPED_FILES to test and mmap_input<> if it is set @@ -22,7 +22,7 @@ namespace TAO_PEGTL_NAMESPACE #else -int main( int, char** ) +int main() { return 0; } diff --git a/packages/PEGTL/src/test/pegtl/file_read.cpp b/packages/PEGTL/src/test/pegtl/file_read.cpp index 85bd80d53a805cdee10ccff553f2293334b653c4..00b0184ee21b5190136da3c3334549a952f87bee 100644 --- a/packages/PEGTL/src/test/pegtl/file_read.cpp +++ b/packages/PEGTL/src/test/pegtl/file_read.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -12,13 +12,11 @@ namespace TAO_PEGTL_NAMESPACE { explicit open_input( const char* in_filename ) : read_input< P, Eol >( internal::file_open( in_filename ), in_filename ) - { - } + {} explicit open_input( const std::string& in_filename ) : open_input( in_filename.c_str() ) - { - } + {} }; void unit_test() diff --git a/packages/PEGTL/src/test/pegtl/internal_endian.cpp b/packages/PEGTL/src/test/pegtl/internal_endian.cpp index 0dcfa983fc90cf5708c087cfc80963e0419fefbf..6319a70cec05a650de1f4f89684c09a31dd83eb6 100644 --- a/packages/PEGTL/src/test/pegtl/internal_endian.cpp +++ b/packages/PEGTL/src/test/pegtl/internal_endian.cpp @@ -1,7 +1,7 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#include <tao/pegtl/internal/endian.hpp> +#include <tao/pegtl/contrib/internal/endian.hpp> #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp b/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp index be408e037a3fb16f1656e7d1a2829aa05560015d..567ed28a6e1a1acd846e5831f00eba31cfb008e1 100644 --- a/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp +++ b/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <tao/pegtl/file_input.hpp> @@ -30,7 +30,7 @@ namespace TAO_PEGTL_NAMESPACE #else -int main( int, char** ) +int main() { return 0; } diff --git a/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp b/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp index aa1134b5afe2bcc96f8ae7e4ce4ff5c794aa27c2..3a3dc3c2c8a6ab40678c4563bba8112f6aa9a1e7 100644 --- a/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp +++ b/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <tao/pegtl/file_input.hpp> @@ -29,7 +29,7 @@ namespace TAO_PEGTL_NAMESPACE #else -int main( int, char** ) +int main() { return 0; } diff --git a/packages/PEGTL/src/test/pegtl/main.hpp b/packages/PEGTL/src/test/pegtl/main.hpp index c72e13b031452322b40b9e0080ff7cc515aefda8..3b92ee527c403f6f0961ce2eba2b313225cb9a08 100644 --- a/packages/PEGTL/src/test/pegtl/main.hpp +++ b/packages/PEGTL/src/test/pegtl/main.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_MAIN_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_MAIN_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_MAIN_HPP #include <cstdlib> diff --git a/packages/PEGTL/src/test/pegtl/pegtl_string_t.cpp b/packages/PEGTL/src/test/pegtl/pegtl_string_t.cpp index 0a7c584397bc0429b59633cc8ea9108ca38d2452..2118e393428a6e29c90e87649a5c8c6822737c37 100644 --- a/packages/PEGTL/src/test/pegtl/pegtl_string_t.cpp +++ b/packages/PEGTL/src/test/pegtl/pegtl_string_t.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <type_traits> @@ -10,13 +10,13 @@ namespace test { // We only need to test that this compiles... - struct foo : TAO_PEGTL_STRING( "foo" ) - { - }; + struct foo + : TAO_PEGTL_STRING( "foo" ) + {}; - struct foobar : TAO_PEGTL_NAMESPACE::sor< TAO_PEGTL_STRING( "foo" ), TAO_PEGTL_STRING( "bar" ) > - { - }; + struct foobar + : TAO_PEGTL_NAMESPACE::sor< TAO_PEGTL_STRING( "foo" ), TAO_PEGTL_STRING( "bar" ) > + {}; static_assert( std::is_same_v< TAO_PEGTL_STRING( "Hello" ), TAO_PEGTL_NAMESPACE::string< 'H', 'e', 'l', 'l', 'o' > > ); static_assert( !std::is_same_v< TAO_PEGTL_ISTRING( "Hello" ), TAO_PEGTL_NAMESPACE::string< 'H', 'e', 'l', 'l', 'o' > > ); @@ -30,7 +30,7 @@ namespace test // The strings currently have a maximum length of 512 characters. - using namespace TAO_PEGTL_NAMESPACE::alphabet; // NOLINT + using namespace TAO_PEGTL_NAMESPACE::alphabet; static_assert( std::is_same_v< TAO_PEGTL_STRING( "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" ), TAO_PEGTL_NAMESPACE::string< 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, 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 > > ); diff --git a/packages/PEGTL/src/test/pegtl/position.cpp b/packages/PEGTL/src/test/pegtl/position.cpp index 1ea3ed24051583d5c99d1b8c18935ac7c7cc588a..92e8e45a0d64692e4bc42ab02c1ca54df1667749 100644 --- a/packages/PEGTL/src/test/pegtl/position.cpp +++ b/packages/PEGTL/src/test/pegtl/position.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -12,40 +12,39 @@ namespace TAO_PEGTL_NAMESPACE { buffer_input_t( const std::string& in_string, const std::string& in_source ) : buffer_input< internal::cstring_reader >( in_source, 42, in_string.c_str() ) - { - } + {} }; - template< typename Rule, typename Input = memory_input<> > + template< typename Rule, typename ParseInput = memory_input<> > void test_matches_lf() { static const std::string s1 = "\n"; - Input i1( s1, __FUNCTION__ ); + ParseInput i1( s1, __FUNCTION__ ); TAO_PEGTL_TEST_ASSERT( parse< Rule >( i1 ) ); TAO_PEGTL_TEST_ASSERT( i1.line() == 2 ); TAO_PEGTL_TEST_ASSERT( i1.byte_in_line() == 0 ); } - template< typename Rule, typename Input = memory_input<> > + template< typename Rule, typename ParseInput = memory_input<> > void test_matches_other( const std::string& s2 ) { TAO_PEGTL_TEST_ASSERT( s2.size() == 1 ); - Input i2( s2, __FUNCTION__ ); + ParseInput i2( s2, __FUNCTION__ ); TAO_PEGTL_TEST_ASSERT( parse< Rule >( i2 ) ); TAO_PEGTL_TEST_ASSERT( i2.line() == 1 ); TAO_PEGTL_TEST_ASSERT( i2.byte_in_line() == 1 ); } - template< typename Rule, typename Input = memory_input<> > + template< typename Rule, typename ParseInput = memory_input<> > void test_mismatch( const std::string& s3 ) { TAO_PEGTL_TEST_ASSERT( s3.size() == 1 ); - Input i3( s3, __FUNCTION__ ); + ParseInput i3( s3, __FUNCTION__ ); TAO_PEGTL_TEST_ASSERT( !parse< Rule >( i3 ) ); TAO_PEGTL_TEST_ASSERT( i3.line() == 1 ); @@ -67,8 +66,8 @@ namespace TAO_PEGTL_NAMESPACE template<> struct outer_action< two< 'b' > > { - template< typename Input > - static void apply( const Input& oi ) + template< typename ActionInput > + static void apply( const ActionInput& oi ) { const auto p = oi.position(); TAO_PEGTL_TEST_ASSERT( p.source == "outer" ); @@ -80,7 +79,7 @@ namespace TAO_PEGTL_NAMESPACE } }; - template< typename Input = memory_input<> > + template< typename ParseInput = memory_input<> > void test_nested() { try { diff --git a/packages/PEGTL/src/test/pegtl/result_type.hpp b/packages/PEGTL/src/test/pegtl/result_type.hpp index 1d5c89c4cbce107a7fc9fcffcd2f03801c7fbf40..887fdde983fac1cddb8ec972ada6ba93b6601997 100644 --- a/packages/PEGTL/src/test/pegtl/result_type.hpp +++ b/packages/PEGTL/src/test/pegtl/result_type.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_RESULT_TYPE_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_RESULT_TYPE_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_RESULT_TYPE_HPP #include <ostream> diff --git a/packages/PEGTL/src/test/pegtl/rule_action.cpp b/packages/PEGTL/src/test/pegtl/rule_action.cpp index c7429f89164e51e096df78a9ac5ae4889d17c05d..6b0c1c0dc0f11c0eefc7d50b512d49837ee42ee0 100644 --- a/packages/PEGTL/src/test/pegtl/rule_action.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_action.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -11,6 +11,10 @@ namespace TAO_PEGTL_NAMESPACE void unit_test() { + verify_meta< action< nothing >, internal::success >(); + verify_meta< action< nothing, eof >, internal::action< nothing, eof >, eof >(); + verify_meta< action< nothing, eof, any >, internal::action< nothing, internal::seq< eof, any > >, internal::seq< eof, any > >(); + verify_seqs< test_action_rule >(); } diff --git a/packages/PEGTL/src/test/pegtl/rule_apply.cpp b/packages/PEGTL/src/test/pegtl/rule_apply.cpp index 4f64066e6b903558b2462d51867d5367623be058..92bf49220e739f065c782161800b5156ed46a9a6 100644 --- a/packages/PEGTL/src/test/pegtl/rule_apply.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_apply.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -11,8 +11,8 @@ namespace TAO_PEGTL_NAMESPACE { struct action_a { - template< typename Input > - static void apply( const Input& /*unused*/, int& r, int& s ) + template< typename ActionInput > + static void apply( const ActionInput& /*unused*/, int& r, int& s ) { TAO_PEGTL_TEST_ASSERT( !r ); TAO_PEGTL_TEST_ASSERT( !s ); @@ -22,8 +22,8 @@ namespace TAO_PEGTL_NAMESPACE struct action_b { - template< typename Input > - static bool apply( const Input& /*unused*/, int& r, int& s ) + template< typename ActionInput > + static bool apply( const ActionInput& /*unused*/, int& r, int& s ) { TAO_PEGTL_TEST_ASSERT( !s ); TAO_PEGTL_TEST_ASSERT( r == 1 ); @@ -34,8 +34,8 @@ namespace TAO_PEGTL_NAMESPACE struct action2_a { - template< typename Input > - static void apply( const Input& /*unused*/, bool& state_b ) + template< typename ActionInput > + static void apply( const ActionInput& /*unused*/, bool& state_b ) { TAO_PEGTL_TEST_ASSERT( !state_b ); } @@ -43,8 +43,8 @@ namespace TAO_PEGTL_NAMESPACE struct action2_b { - template< typename Input > - static bool apply( const Input& /*unused*/, bool& state_b ) + template< typename ActionInput > + static bool apply( const ActionInput& /*unused*/, bool& state_b ) { TAO_PEGTL_TEST_ASSERT( !state_b ); state_b = true; @@ -54,8 +54,8 @@ namespace TAO_PEGTL_NAMESPACE struct action2_c { - template< typename Input > - static void apply( const Input& /*unused*/, bool& /*unused*/ ) + template< typename ActionInput > + static void apply( const ActionInput& /*unused*/, bool& /*unused*/ ) { TAO_PEGTL_TEST_ASSERT( false ); } @@ -79,12 +79,14 @@ namespace TAO_PEGTL_NAMESPACE TAO_PEGTL_TEST_ASSERT( !result ); TAO_PEGTL_TEST_ASSERT( state_b ); + verify_meta< apply< test1::action_a, test1::action_b >, internal::apply< test1::action_a, test1::action_b > >(); + verify_analyze< apply<> >( __LINE__, __FILE__, false, false ); verify_rule< apply<> >( __LINE__, __FILE__, "", result_type::success, 0 ); for( char i = 1; i < 127; ++i ) { - char t[] = { i, 0 }; // NOLINT + char t[] = { i, 0 }; verify_rule< apply<> >( __LINE__, __FILE__, std::string( t ), result_type::success, 1 ); } } diff --git a/packages/PEGTL/src/test/pegtl/rule_apply0.cpp b/packages/PEGTL/src/test/pegtl/rule_apply0.cpp index e3b27ee2f70d5a44512b26213c317eeaced3e403..4a25a5b3922409bcaa610d1b4fd7e019a1fbe094 100644 --- a/packages/PEGTL/src/test/pegtl/rule_apply0.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_apply0.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -74,12 +74,14 @@ namespace TAO_PEGTL_NAMESPACE TAO_PEGTL_TEST_ASSERT( !result ); TAO_PEGTL_TEST_ASSERT( state_b ); + verify_meta< apply0< test1::action_a, test1::action_b >, internal::apply0< test1::action_a, test1::action_b > >(); + verify_analyze< apply0<> >( __LINE__, __FILE__, false, false ); verify_rule< apply0<> >( __LINE__, __FILE__, "", result_type::success, 0 ); for( char i = 1; i < 127; ++i ) { - char t[] = { i, 0 }; // NOLINT + char t[] = { i, 0 }; verify_rule< apply0<> >( __LINE__, __FILE__, std::string( t ), result_type::success, 1 ); } } diff --git a/packages/PEGTL/src/test/pegtl/rule_at.cpp b/packages/PEGTL/src/test/pegtl/rule_at.cpp index 6f73c253b658ee6452ebbe7c741934c9f677400d..3d7f6dd484ed45ca35161a6476779f30f2c61c95 100644 --- a/packages/PEGTL/src/test/pegtl/rule_at.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_at.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -16,8 +16,7 @@ namespace TAO_PEGTL_NAMESPACE template<> struct at_action< any > { - template< typename Input > - static void apply( const Input& /*unused*/ ) + static void apply0() { ++at_counter; } @@ -27,6 +26,10 @@ namespace TAO_PEGTL_NAMESPACE { TAO_PEGTL_TEST_ASSERT( at_counter == 0 ); + verify_meta< at<>, internal::success >(); + verify_meta< at< eof >, internal::at< eof >, eof >(); + verify_meta< at< eof, any >, internal::at< internal::seq< eof, any > >, internal::seq< eof, any > >(); + verify_analyze< at< eof > >( __LINE__, __FILE__, false, false ); verify_analyze< at< any > >( __LINE__, __FILE__, false, false ); diff --git a/packages/PEGTL/src/test/pegtl/rule_bof.cpp b/packages/PEGTL/src/test/pegtl/rule_bof.cpp index ff44dbef1d1413ba6ad53292673446b866036a0e..ee02311678a3825ed5eafe01ad55a3ebe8f1ecc6 100644 --- a/packages/PEGTL/src/test/pegtl/rule_bof.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_bof.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -9,12 +9,14 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< bof, internal::bof >(); + verify_analyze< bof >( __LINE__, __FILE__, false, false ); verify_rule< bof >( __LINE__, __FILE__, "", result_type::success, 0 ); for( char i = 1; i < 127; ++i ) { - const char s[] = { i, 0 }; // NOLINT + const char s[] = { i, 0 }; verify_rule< bof >( __LINE__, __FILE__, s, result_type::success, 1 ); } verify_rule< seq< alpha, bof > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 ); diff --git a/packages/PEGTL/src/test/pegtl/rule_bol.cpp b/packages/PEGTL/src/test/pegtl/rule_bol.cpp index 60852c6d8aedcd1e97e3935733df98b701dcfd5b..d50a41bbedba9aa926a55784b3019fe599bd2f46 100644 --- a/packages/PEGTL/src/test/pegtl/rule_bol.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_bol.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -9,12 +9,14 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< bol, internal::bol >(); + verify_analyze< bol >( __LINE__, __FILE__, false, false ); verify_only< bol >( __LINE__, __FILE__, "", result_type::success, 0 ); for( char i = 1; i < 127; ++i ) { - const char s[] = { i, 0 }; // NOLINT + const char s[] = { i, 0 }; verify_only< bol >( __LINE__, __FILE__, s, result_type::success, 1 ); } verify_only< seq< alpha, bol > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 ); diff --git a/packages/PEGTL/src/test/pegtl/rule_bytes.cpp b/packages/PEGTL/src/test/pegtl/rule_bytes.cpp index ad9462640cd24af2a5ea367b3c0258c179da26ce..9485df93ff904fbc19338ed999d033c1ee8716c0 100644 --- a/packages/PEGTL/src/test/pegtl/rule_bytes.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_bytes.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -10,6 +10,10 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< bytes< 0 >, internal::success >(); + verify_meta< bytes< 1 >, internal::bytes< 1 > >(); + verify_meta< bytes< 42 >, internal::bytes< 42 > >(); + verify_analyze< bytes< 0 > >( __LINE__, __FILE__, false, false ); verify_rule< bytes< 0 > >( __LINE__, __FILE__, "", result_type::success, 0 ); diff --git a/packages/PEGTL/src/test/pegtl/rule_control.cpp b/packages/PEGTL/src/test/pegtl/rule_control.cpp index c4cc810da2165794086d10a4fd0572c3122b7e3d..7153086e24c9e34bdcbd0d5ddc56fec1e54a6fee 100644 --- a/packages/PEGTL/src/test/pegtl/rule_control.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_control.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -11,6 +11,10 @@ namespace TAO_PEGTL_NAMESPACE void unit_test() { + verify_meta< control< normal >, internal::success >(); + verify_meta< control< normal, eof >, internal::control< normal, eof >, eof >(); + verify_meta< control< normal, eof, any >, internal::control< normal, internal::seq< eof, any > >, internal::seq< eof, any > >(); + verify_seqs< test_control_rule >(); } diff --git a/packages/PEGTL/src/test/pegtl/rule_disable.cpp b/packages/PEGTL/src/test/pegtl/rule_disable.cpp index db15b8a1ece34ca1ac32519f454608c0d63a01e8..f48626d9e5be265c60b4a988cd5e66e8f7b2b9b6 100644 --- a/packages/PEGTL/src/test/pegtl/rule_disable.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_disable.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -8,6 +8,10 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< disable<>, internal::success >(); + verify_meta< disable< eof >, internal::disable< eof >, eof >(); + verify_meta< disable< eof, any >, internal::disable< internal::seq< eof, any > >, internal::seq< eof, any > >(); + verify_seqs< disable >(); } diff --git a/packages/PEGTL/src/test/pegtl/rule_enable.cpp b/packages/PEGTL/src/test/pegtl/rule_enable.cpp index de998a6e30c1c932a5208b2dccef0bf1fb202801..121b18ce458da1c145df3f132f74fbb8ee3975e0 100644 --- a/packages/PEGTL/src/test/pegtl/rule_enable.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_enable.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -8,6 +8,10 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< enable<>, internal::success >(); + verify_meta< enable< eof >, internal::enable< eof >, eof >(); + verify_meta< enable< eof, any >, internal::enable< internal::seq< eof, any > >, internal::seq< eof, any > >(); + verify_seqs< enable >(); } diff --git a/packages/PEGTL/src/test/pegtl/rule_eof.cpp b/packages/PEGTL/src/test/pegtl/rule_eof.cpp index ccb1809f14cbc2b30f7df6285ccc9b2cccf2ba8a..2d200d564fc3b920ebe9cf120e0550fe5bd0f725 100644 --- a/packages/PEGTL/src/test/pegtl/rule_eof.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_eof.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -10,6 +10,8 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< eof, internal::eof >(); + verify_analyze< eof >( __LINE__, __FILE__, false, false ); verify_rule< eof >( __LINE__, __FILE__, "", result_type::success, 0 ); diff --git a/packages/PEGTL/src/test/pegtl/rule_failure.cpp b/packages/PEGTL/src/test/pegtl/rule_failure.cpp index 01105fed25200931f1a673be0a3ac04678544eb3..2f116fa201fccec496bdf9a7d9deaf6a2db7288a 100644 --- a/packages/PEGTL/src/test/pegtl/rule_failure.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_failure.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -10,6 +10,8 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< failure, internal::failure >(); + verify_analyze< failure >( __LINE__, __FILE__, true, false ); // "Success implies consumption" is true because "success" never happens. verify_rule< failure >( __LINE__, __FILE__, "", result_type::local_failure, 0 ); diff --git a/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp b/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp index ab9576511f4dde1586fd771a28bb188257d275e4..82d3cb7bfe7d7e49acc1b60815bc3cc1c47b1c94 100644 --- a/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -10,8 +10,8 @@ namespace TAO_PEGTL_NAMESPACE { struct action_a { - template< typename Input > - static void apply( const Input& in, std::string& r, std::string& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& r, std::string& s ) { TAO_PEGTL_TEST_ASSERT( r.empty() ); TAO_PEGTL_TEST_ASSERT( s.empty() ); @@ -21,8 +21,8 @@ namespace TAO_PEGTL_NAMESPACE struct action_b { - template< typename Input > - static void apply( const Input& in, std::string& r, std::string& s ) + template< typename ActionInput > + static void apply( const ActionInput& in, std::string& r, std::string& s ) { TAO_PEGTL_TEST_ASSERT( s.empty() ); s += in.string(); @@ -33,8 +33,8 @@ namespace TAO_PEGTL_NAMESPACE struct action2_a { - template< typename Input > - static void apply( const Input& in, bool& state_b ) + template< typename ActionInput > + static void apply( const ActionInput& in, bool& state_b ) { TAO_PEGTL_TEST_ASSERT( in.string_view() == "foo" ); TAO_PEGTL_TEST_ASSERT( !state_b ); @@ -43,8 +43,8 @@ namespace TAO_PEGTL_NAMESPACE struct action2_b { - template< typename Input > - static bool apply( const Input& in, bool& state_b ) + template< typename ActionInput > + static bool apply( const ActionInput& in, bool& state_b ) { TAO_PEGTL_TEST_ASSERT( in.string_view() == "foo" ); TAO_PEGTL_TEST_ASSERT( !state_b ); @@ -55,8 +55,8 @@ namespace TAO_PEGTL_NAMESPACE struct action2_c { - template< typename Input > - static void apply( const Input& /*unused*/, bool& /*unused*/ ) + template< typename ActionInput > + static void apply( const ActionInput& /*unused*/, bool& /*unused*/ ) { TAO_PEGTL_TEST_ASSERT( false ); } @@ -114,6 +114,8 @@ namespace TAO_PEGTL_NAMESPACE TAO_PEGTL_TEST_ASSERT( !result ); TAO_PEGTL_TEST_ASSERT( !state_b ); } + verify_meta< if_apply< any >, internal::if_apply< any >, any >(); + verify_meta< if_apply< any, test1::action_a >, internal::if_apply< any, test1::action_a >, any >(); verify_seqs< if_apply_seq >(); verify_seqs< if_apply_disable >(); diff --git a/packages/PEGTL/src/test/pegtl/rule_if_must.cpp b/packages/PEGTL/src/test/pegtl/rule_if_must.cpp index 8900d8186bae85608f0fa1c0b403ac8b8e34a5af..51ef74024c5e9bc45e83701b1f4c8fde7e5a10c2 100644 --- a/packages/PEGTL/src/test/pegtl/rule_if_must.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_if_must.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -9,6 +9,10 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< if_must< any >, internal::if_must< false, any >, any, internal::must<> >(); + verify_meta< if_must< any, eof >, internal::if_must< false, any, eof >, any, internal::must< eof > >(); + verify_meta< if_must< any, eof, one< 0 > >, internal::if_must< false, any, eof, one< 0 > >, any, internal::must< eof, one< 0 > > >(); + verify_analyze< if_must< any, any > >( __LINE__, __FILE__, true, false ); verify_analyze< if_must< eof, any > >( __LINE__, __FILE__, true, false ); verify_analyze< if_must< opt< any >, any > >( __LINE__, __FILE__, true, false ); diff --git a/packages/PEGTL/src/test/pegtl/rule_if_must_else.cpp b/packages/PEGTL/src/test/pegtl/rule_if_must_else.cpp index b8fe63c6ceff4b9b9f914be3343ac03ccf49a108..8fae642416e00ef4f5e67896ac93bcd9356876c4 100644 --- a/packages/PEGTL/src/test/pegtl/rule_if_must_else.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_if_must_else.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp b/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp index 7dac12c7ba2b0f202c3f02cf5c1ff668dd136233..c31c540349ce1daa7a593a724b979a07b79b4f3d 100644 --- a/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -8,6 +8,8 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< if_then_else< digit, alpha, print >, internal::if_then_else< digit, alpha, print >, digit, alpha, print >(); + verify_ifmt< if_then_else >(); } diff --git a/packages/PEGTL/src/test/pegtl/rule_list.cpp b/packages/PEGTL/src/test/pegtl/rule_list.cpp index bed729ec803f4dde68c29c16af6e8c4be04c6c08..08748154bc642f35494232acec7f526c323f3fe6 100644 --- a/packages/PEGTL/src/test/pegtl/rule_list.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_list.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_list_must.cpp b/packages/PEGTL/src/test/pegtl/rule_list_must.cpp index e2f2b7fe5ee85a7168bbf8a434ec0e6ea8fd672b..980a4214dc75169bf3749003187aa520a8ccce77 100644 --- a/packages/PEGTL/src/test/pegtl/rule_list_must.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_list_must.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp b/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp index 50378895c8ed348dce8e21779408d7e54c1f45c2..02b18f1c5d62ade3db9698d1a7c606fb46f9b779 100644 --- a/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_minus.cpp b/packages/PEGTL/src/test/pegtl/rule_minus.cpp index 2fc804c7ea56311458b7c8cdc2cf85759f3a8ba2..b7c3431b30d899063fb5374d4660a33d26f83a19 100644 --- a/packages/PEGTL/src/test/pegtl/rule_minus.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_minus.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2016-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_must.cpp b/packages/PEGTL/src/test/pegtl/rule_must.cpp index 8bbdfc999590bea2a8e2d65d3ece13c56697ca9a..b93354ff07427b227ffc3e01a2ab01ae11d9d80a 100644 --- a/packages/PEGTL/src/test/pegtl/rule_must.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_must.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -8,6 +8,10 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { + verify_meta< must<>, internal::success >(); + verify_meta< must< alpha >, internal::must< alpha >, alpha >(); + verify_meta< must< alpha, digit >, internal::seq< internal::must< alpha >, internal::must< digit > >, internal::must< alpha >, internal::must< digit > >(); + verify_seqs< must >( result_type::global_failure ); } diff --git a/packages/PEGTL/src/test/pegtl/rule_not_at.cpp b/packages/PEGTL/src/test/pegtl/rule_not_at.cpp index 4ad66acd8c743a1f9a64efdd87e579b8501f2b0a..7fe69a528d45ab2e6501c1d0f4abee690c685ff7 100644 --- a/packages/PEGTL/src/test/pegtl/rule_not_at.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_not_at.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -16,8 +16,7 @@ namespace TAO_PEGTL_NAMESPACE template<> struct at_action< alpha > { - template< typename Input > - static void apply( const Input& /*unused*/ ) + static void apply0() { ++at_counter; } @@ -27,6 +26,10 @@ namespace TAO_PEGTL_NAMESPACE { TAO_PEGTL_TEST_ASSERT( at_counter == 0 ); + verify_meta< not_at<>, internal::failure >(); + verify_meta< not_at< eof >, internal::not_at< eof >, eof >(); + verify_meta< not_at< eof, any >, internal::not_at< internal::seq< eof, any > >, internal::seq< eof, any > >(); + verify_analyze< not_at< eof > >( __LINE__, __FILE__, false, false ); verify_analyze< not_at< any > >( __LINE__, __FILE__, false, false ); diff --git a/packages/PEGTL/src/test/pegtl/rule_opt.cpp b/packages/PEGTL/src/test/pegtl/rule_opt.cpp index 951bdb7419da9bb262354f39d37cfe7b48aac966..05507c8c559c188671408d4dd3fdb7cbc71af81c 100644 --- a/packages/PEGTL/src/test/pegtl/rule_opt.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_opt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -22,6 +22,10 @@ namespace TAO_PEGTL_NAMESPACE void unit_test() { + verify_meta< opt<>, internal::success >(); + verify_meta< opt< eof >, internal::opt< eof >, eof >(); + verify_meta< opt< eof, any >, internal::opt< internal::seq< eof, any > >, internal::seq< eof, any > >(); + verify_analyze< opt< any > >( __LINE__, __FILE__, false, false ); verify_analyze< opt< eof > >( __LINE__, __FILE__, false, false ); diff --git a/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp b/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp index cd06deea9851f3a223e940ad46c07f237b66fb35..783b0d994cb14c8b9bda715ce80b7f527433c5c7 100644 --- a/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_pad.cpp b/packages/PEGTL/src/test/pegtl/rule_pad.cpp index 6cb6fe5fd6e02936ea6b4d2c36b000111ed7c4ae..5e495b7d587dcb7602a3ed8c3de4e5528e2b1714 100644 --- a/packages/PEGTL/src/test/pegtl/rule_pad.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_pad.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp b/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp index d16c5064a453a056d23bd3f80725428c57140f5c..7b63fcd7566a8e8c2182ea56821f2f7ed7aea59e 100644 --- a/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_plus.cpp b/packages/PEGTL/src/test/pegtl/rule_plus.cpp index 251cf15bee1d482d2875dc94f0e30a19536a726b..6882ebfced1f7765c662060b070fff3667ab24d7 100644 --- a/packages/PEGTL/src/test/pegtl/rule_plus.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_plus.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_rematch.cpp b/packages/PEGTL/src/test/pegtl/rule_rematch.cpp index d6d384469a350c37ca0f1b3998dfb8529438581f..6eec3dba03df0aa960660d090371929d39e2845e 100644 --- a/packages/PEGTL/src/test/pegtl/rule_rematch.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_rematch.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -9,15 +9,33 @@ namespace TAO_PEGTL_NAMESPACE { void unit_test() { - verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "c", result_type::success, 0 ); - verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 ); - verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "b", result_type::local_failure, 1 ); + verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "c", result_type::success ); + verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "a", result_type::local_failure ); + verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "b", result_type::local_failure ); verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "cc", result_type::success, 1 ); - verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "bc", result_type::local_failure, 2 ); + verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "bc", result_type::local_failure ); verify_analyze< rematch< alpha, digit > >( __LINE__, __FILE__, true, false ); verify_analyze< rematch< opt< alpha >, digit > >( __LINE__, __FILE__, false, false ); - + verify_analyze< rematch< alnum, opt< alpha > > >( __LINE__, __FILE__, true, false ); + { + struct foo + : rematch< foo, alnum > + {}; + verify_analyze< foo >( __LINE__, __FILE__, false, true ); + } + { + struct foo + : rematch< alnum, foo > + {}; + verify_analyze< foo >( __LINE__, __FILE__, true, true ); + } + { + struct foo + : rematch< alnum, alpha, foo > + {}; + verify_analyze< foo >( __LINE__, __FILE__, true, true ); + } verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "", result_type::local_failure, 0 ); verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1", result_type::success, 0 ); verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 ); @@ -45,12 +63,12 @@ namespace TAO_PEGTL_NAMESPACE verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "12", result_type::success, 1 ); verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "1c", result_type::success, 1 ); - verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "", result_type::local_failure, 0 ); - verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1", result_type::success, 0 ); - verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 ); - verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 ); + verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "", result_type::local_failure ); + verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1", result_type::success ); + verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a", result_type::local_failure ); + verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "%", result_type::local_failure ); verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1%", result_type::success, 1 ); - verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure, 1 ); + verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure ); verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "12", result_type::success, 0 ); verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1c", result_type::success, 0 ); verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "aa", result_type::local_failure, 2 ); @@ -62,7 +80,7 @@ namespace TAO_PEGTL_NAMESPACE verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 ); verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 ); verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1%", result_type::success, 1 ); - verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a%", result_type::local_failure, 1 ); + verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a%", result_type::local_failure ); verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "12", result_type::success, 0 ); verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1c", result_type::success, 0 ); verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "aa", result_type::local_failure, 2 ); diff --git a/packages/PEGTL/src/test/pegtl/rule_rep.cpp b/packages/PEGTL/src/test/pegtl/rule_rep.cpp index 0c54cd8512bcd14b1f17a77069c43ebb0c3eded0..d57410382c60e1940b46ea148b32990f45122fea 100644 --- a/packages/PEGTL/src/test/pegtl/rule_rep.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_rep.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp index 60dfb0b341656786f7b038e6456f2755078cbd33..09b52e8587b2845cfdc5b4bba324c2675a5e48fa 100644 --- a/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp index 20a33d5ebb0ae6cac7b5d9e011837ddeaa183c76..73fc6ea3797ac73125756d4dd7ad9700d132f4ed 100644 --- a/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp index 8ad8a1119a7ec5b32f61aa4158c32fa418479d59..0833aa62c5b558f9f8bd555f272c33a3037e46cf 100644 --- a/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp index 2e232f769405d202a4cdaeef4a6242a7c758507f..4c66f6eac4070464a368a8c86b51dfeac70fb9a3 100644 --- a/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_require.cpp b/packages/PEGTL/src/test/pegtl/rule_require.cpp index 0a8e389edb75ea31c2647f5e7551642dda3f3d58..0d2ce914743f822b7cd8cb7f31ccca0c1b02e56d 100644 --- a/packages/PEGTL/src/test/pegtl/rule_require.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_require.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_seq.cpp b/packages/PEGTL/src/test/pegtl/rule_seq.cpp index 686d6ba9c5557bb6f014c511c8cb9d055beabffb..22505494a0df37cfee9b0523ef65df5b4335d9c9 100644 --- a/packages/PEGTL/src/test/pegtl/rule_seq.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_seq.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_sor.cpp b/packages/PEGTL/src/test/pegtl/rule_sor.cpp index 01385de8477cd6c9c14590541871e5f55d431cf6..b0792b4432c7b68b6f14ac4cbe3fa87c3aa2d69c 100644 --- a/packages/PEGTL/src/test/pegtl/rule_sor.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_sor.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_star.cpp b/packages/PEGTL/src/test/pegtl/rule_star.cpp index 1689eaff6aece9b6073ccef19a1fe1f67a48e808..8cfaa6ca695a69d54eac63338bac3c5dbaa93215 100644 --- a/packages/PEGTL/src/test/pegtl/rule_star.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_star.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_star_must.cpp b/packages/PEGTL/src/test/pegtl/rule_star_must.cpp index b2300c8f723be4045371b5580dfaf9eed1e66da5..e0f863a3f45860fab3940b56f250067ef9e5d26b 100644 --- a/packages/PEGTL/src/test/pegtl/rule_star_must.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_star_must.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_state.cpp b/packages/PEGTL/src/test/pegtl/rule_state.cpp index 34560037b42abd5736d003bd36f81bd95e289dd2..77ed17f01bb18186b64b8f6a6b2dd2ffa7647d0b 100644 --- a/packages/PEGTL/src/test/pegtl/rule_state.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_state.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -8,15 +8,13 @@ namespace TAO_PEGTL_NAMESPACE { struct test_state_state { - template< typename Input > - explicit test_state_state( const Input& /*unused*/ ) - { - } + template< typename ParseInput > + explicit test_state_state( const ParseInput& /*unused*/ ) + {} - template< typename Input > - void success( const Input& /*unused*/ ) const - { - } + template< typename ParseInput > + void success( const ParseInput& /*unused*/ ) const + {} }; template< typename... Rules > diff --git a/packages/PEGTL/src/test/pegtl/rule_success.cpp b/packages/PEGTL/src/test/pegtl/rule_success.cpp index 08e4185fc017a87050763cd601b6b73c33636d13..fcaff87acb0fd6f9562dedb90f4c7fd2ba78116e 100644 --- a/packages/PEGTL/src/test/pegtl/rule_success.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_success.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -14,7 +14,7 @@ namespace TAO_PEGTL_NAMESPACE verify_rule< success >( __LINE__, __FILE__, "", result_type::success, 0 ); for( char i = 1; i < 127; ++i ) { - char t[] = { i, 0 }; // NOLINT + char t[] = { i, 0 }; verify_rule< success >( __LINE__, __FILE__, std::string( t ), result_type::success, 1 ); } } diff --git a/packages/PEGTL/src/test/pegtl/rule_try_catch.cpp b/packages/PEGTL/src/test/pegtl/rule_try_catch.cpp index 646aa86fdd93506bac293793ffe2f7264d1336d6..4259db331f94ed75b2ba613ff6ca262307831219 100644 --- a/packages/PEGTL/src/test/pegtl/rule_try_catch.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_try_catch.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/rule_until.cpp b/packages/PEGTL/src/test/pegtl/rule_until.cpp index 10f315c77993240f4a9dfefe4c86ac59804a7fb9..f1e49d3946460dcf36194298c3a3b4f07ea7128d 100644 --- a/packages/PEGTL/src/test/pegtl/rule_until.cpp +++ b/packages/PEGTL/src/test/pegtl/rule_until.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" @@ -15,9 +15,9 @@ namespace TAO_PEGTL_NAMESPACE class Action, template< typename... > class Control, - typename Input, + typename ParseInput, typename... States > - static bool match( Input& /*unused*/, bool& v, States... /*unused*/ ) + static bool match( ParseInput& /*unused*/, bool& v, States... /*unused*/ ) { return v; } diff --git a/packages/PEGTL/src/test/pegtl/test.hpp b/packages/PEGTL/src/test/pegtl/test.hpp index e00d7b47c5537a738f8df99bd571fc25f907cf5f..18868e018cd60583c214a4073059bb9aaa193f71 100644 --- a/packages/PEGTL/src/test/pegtl/test.hpp +++ b/packages/PEGTL/src/test/pegtl/test.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_TEST_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_TEST_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_TEST_HPP #include <cstddef> @@ -11,7 +11,7 @@ namespace TAO_PEGTL_NAMESPACE { - std::size_t failed = 0; // NOLINT + std::size_t failed = 0; } // namespace TAO_PEGTL_NAMESPACE @@ -67,32 +67,4 @@ namespace TAO_PEGTL_NAMESPACE } \ } while( false ) -namespace TAO_PEGTL_NAMESPACE -{ - template< unsigned Size, apply_mode B, rewind_mode N, typename... Rules > - struct test_rule - { - using analyze_t = typename seq< Rules... >::analyze_t; - - template< apply_mode A, - rewind_mode M, - template< typename... > - class Action, - template< typename... > - class Control, - typename Input, - typename... States > - static bool match( Input& in, States&&... st ) - { - static_assert( A == B, "unexpected apply mode" ); - static_assert( M == N, "unexpected rewind mode" ); - - TAO_PEGTL_TEST_ASSERT( in.size() == Size ); - - return seq< Rules... >::template match< A, M, Action, Control >( in, st... ); - } - }; - -} // namespace TAO_PEGTL_NAMESPACE - #endif diff --git a/packages/PEGTL/src/test/pegtl/tester.cpp b/packages/PEGTL/src/test/pegtl/tester.cpp index 42fdeceb44261b8dcd37c8b7a21cff89f281dc28..b57abd0aa4dfa4cb7b38462bc7288bc26f17c9b2 100644 --- a/packages/PEGTL/src/test/pegtl/tester.cpp +++ b/packages/PEGTL/src/test/pegtl/tester.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include <iostream> diff --git a/packages/PEGTL/src/test/pegtl/uint16_general.cpp b/packages/PEGTL/src/test/pegtl/uint16_general.cpp index 18e6748eee7ab3c2ace5ab07db8c53308035084f..c43aa51563bb0bd4359fe7184a15e100b740b4c0 100644 --- a/packages/PEGTL/src/test/pegtl/uint16_general.cpp +++ b/packages/PEGTL/src/test/pegtl/uint16_general.cpp @@ -1,10 +1,12 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" #include "verify_char.hpp" #include "verify_rule.hpp" +#include <tao/pegtl/contrib/uint16.hpp> + namespace TAO_PEGTL_NAMESPACE { void unit_test() diff --git a/packages/PEGTL/src/test/pegtl/uint32_general.cpp b/packages/PEGTL/src/test/pegtl/uint32_general.cpp index 4ed62de18774e756fe7e91e54941f32200bbe72a..97430a5a8bd831199f514f75060d7d39b5a56172 100644 --- a/packages/PEGTL/src/test/pegtl/uint32_general.cpp +++ b/packages/PEGTL/src/test/pegtl/uint32_general.cpp @@ -1,10 +1,12 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" #include "verify_char.hpp" #include "verify_rule.hpp" +#include <tao/pegtl/contrib/uint32.hpp> + namespace TAO_PEGTL_NAMESPACE { void unit_test() diff --git a/packages/PEGTL/src/test/pegtl/uint64_general.cpp b/packages/PEGTL/src/test/pegtl/uint64_general.cpp index b32701eedc4fe67eb42a04f238f56366accc6e62..2b5ef5e218d2aa46d6a45d014156ced41b690d49 100644 --- a/packages/PEGTL/src/test/pegtl/uint64_general.cpp +++ b/packages/PEGTL/src/test/pegtl/uint64_general.cpp @@ -1,10 +1,12 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" #include "verify_char.hpp" #include "verify_rule.hpp" +#include <tao/pegtl/contrib/uint64.hpp> + namespace TAO_PEGTL_NAMESPACE { void unit_test() diff --git a/packages/PEGTL/src/test/pegtl/uint8_general.cpp b/packages/PEGTL/src/test/pegtl/uint8_general.cpp index 75ec3268a711a38a787f0968d1c24f7a5c6fa062..20ad2a951e3f279b695c349764bcfe12e1abd85d 100644 --- a/packages/PEGTL/src/test/pegtl/uint8_general.cpp +++ b/packages/PEGTL/src/test/pegtl/uint8_general.cpp @@ -1,10 +1,12 @@ -// Copyright (c) 2018-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" #include "verify_char.hpp" #include "verify_rule.hpp" +#include <tao/pegtl/contrib/uint8.hpp> + namespace TAO_PEGTL_NAMESPACE { void unit_test() diff --git a/packages/PEGTL/src/test/pegtl/utf16_general.cpp b/packages/PEGTL/src/test/pegtl/utf16_general.cpp index 1a9521612ede6d3230f1bc5bae4fd17f2d66fbbb..57c7ba3bb9bf7d590277df5cbb2ca6e13c8a2134 100644 --- a/packages/PEGTL/src/test/pegtl/utf16_general.cpp +++ b/packages/PEGTL/src/test/pegtl/utf16_general.cpp @@ -1,142 +1,144 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" #include "verify_rule.hpp" +#include <tao/pegtl/contrib/utf16.hpp> + namespace TAO_PEGTL_NAMESPACE { namespace { std::string u16s( const char16_t u ) { - return std::string( static_cast< const char* >( static_cast< const void* >( &u ) ), sizeof( u ) ); + return std::string( reinterpret_cast< const char* >( &u ), sizeof( u ) ); } std::string u16s_be( const char16_t v ) { const std::uint16_t u = internal::h_to_be( std::uint16_t( v ) ); - return std::string( static_cast< const char* >( static_cast< const void* >( &u ) ), sizeof( u ) ); + return std::string( reinterpret_cast< const char* >( &u ), sizeof( u ) ); } std::string u16s_le( const char16_t v ) { const std::uint16_t u = internal::h_to_le( std::uint16_t( v ) ); - return std::string( static_cast< const char* >( static_cast< const void* >( &u ) ), sizeof( u ) ); + return std::string( reinterpret_cast< const char* >( &u ), sizeof( u ) ); } } // namespace void test_utf16() { - verify_rule< utf16::any >( __LINE__, __FILE__, "", result_type::local_failure, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, "\x01", result_type::local_failure, 1 ); - verify_rule< utf16::any >( __LINE__, __FILE__, "\xff", result_type::local_failure, 1 ); - - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0 ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 1 ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, " ", result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x00ff ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x0100 ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x0fff ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x1000 ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ), result_type::local_failure, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd900 ), result_type::local_failure, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xde00 ), result_type::local_failure, 0 ); + verify_rule< utf16::any >( __LINE__, __FILE__, "", result_type::local_failure ); + verify_rule< utf16::any >( __LINE__, __FILE__, "\x01", result_type::local_failure ); + verify_rule< utf16::any >( __LINE__, __FILE__, "\xff", result_type::local_failure ); + + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0 ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 1 ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, " ", result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x00ff ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x0100 ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x0fff ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0x1000 ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ), result_type::local_failure ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd900 ), result_type::local_failure ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xde00 ), result_type::local_failure ); verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xfffe ) + " ", result_type::success, 1 ); verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xffff ) + " ", result_type::success, 2 ); verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd7ff ) + u16s( 0xdfff ), result_type::success, 2 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xdc00 ) + u16s( 0xdfff ), result_type::local_failure, 4 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0x0020 ), result_type::local_failure, 4 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0xff20 ), result_type::local_failure, 4 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0xdf00 ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0xdfff ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xdbff ) + u16s( 0xdc00 ), result_type::success, 0 ); - verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xdbff ) + u16s( 0xdfff ), result_type::success, 0 ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xdc00 ) + u16s( 0xdfff ), result_type::local_failure ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0x0020 ), result_type::local_failure ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0xff20 ), result_type::local_failure ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0xdf00 ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xd800 ) + u16s( 0xdfff ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xdbff ) + u16s( 0xdc00 ), result_type::success ); + verify_rule< utf16::any >( __LINE__, __FILE__, u16s( 0xdbff ) + u16s( 0xdfff ), result_type::success ); - verify_rule< utf16::one< 0x20 > >( __LINE__, __FILE__, u16s( 0x20 ), result_type::success, 0 ); - verify_rule< utf16::one< 0x20ac > >( __LINE__, __FILE__, u16s( 0x20ac ), result_type::success, 0 ); - verify_rule< utf16::one< 0x10437 > >( __LINE__, __FILE__, u16s( 0xd801 ) + u16s( 0xdc37 ), result_type::success, 0 ); + verify_rule< utf16::one< 0x20 > >( __LINE__, __FILE__, u16s( 0x20 ), result_type::success ); + verify_rule< utf16::one< 0x20ac > >( __LINE__, __FILE__, u16s( 0x20ac ), result_type::success ); + verify_rule< utf16::one< 0x10437 > >( __LINE__, __FILE__, u16s( 0xd801 ) + u16s( 0xdc37 ), result_type::success ); - verify_rule< utf16::bom >( __LINE__, __FILE__, u16s( 0xfeff ), result_type::success, 0 ); - verify_rule< utf16::bom >( __LINE__, __FILE__, u16s( 0xfffe ), result_type::local_failure, 2 ); + verify_rule< utf16::bom >( __LINE__, __FILE__, u16s( 0xfeff ), result_type::success ); + verify_rule< utf16::bom >( __LINE__, __FILE__, u16s( 0xfffe ), result_type::local_failure ); verify_rule< utf16::string< 0x20, 0x20ac, 0x10437 > >( __LINE__, __FILE__, u16s( 0x20 ) + u16s( 0x20ac ) + u16s( 0xd801 ) + u16s( 0xdc37 ) + u16s( 0x20 ), result_type::success, 2 ); } void test_utf16_be() { - verify_rule< utf16_be::any >( __LINE__, __FILE__, "", result_type::local_failure, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, "\x01", result_type::local_failure, 1 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, "\xff", result_type::local_failure, 1 ); - - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0 ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 1 ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, " ", result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x00ff ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x0100 ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x0fff ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x1000 ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ), result_type::local_failure, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd900 ), result_type::local_failure, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xde00 ), result_type::local_failure, 0 ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, "", result_type::local_failure ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, "\x01", result_type::local_failure ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, "\xff", result_type::local_failure ); + + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0 ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 1 ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, " ", result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x00ff ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x0100 ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x0fff ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0x1000 ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ), result_type::local_failure ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd900 ), result_type::local_failure ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xde00 ), result_type::local_failure ); verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xfffe ) + " ", result_type::success, 1 ); verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xffff ) + " ", result_type::success, 2 ); verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd7ff ) + u16s_be( 0xdfff ), result_type::success, 2 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xdc00 ) + u16s_be( 0xdfff ), result_type::local_failure, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0x0020 ), result_type::local_failure, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0xff20 ), result_type::local_failure, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0xdf00 ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0xdfff ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xdbff ) + u16s_be( 0xdc00 ), result_type::success, 0 ); - verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xdbff ) + u16s_be( 0xdfff ), result_type::success, 0 ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xdc00 ) + u16s_be( 0xdfff ), result_type::local_failure ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0x0020 ), result_type::local_failure ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0xff20 ), result_type::local_failure ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0xdf00 ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xd800 ) + u16s_be( 0xdfff ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xdbff ) + u16s_be( 0xdc00 ), result_type::success ); + verify_rule< utf16_be::any >( __LINE__, __FILE__, u16s_be( 0xdbff ) + u16s_be( 0xdfff ), result_type::success ); - verify_rule< utf16_be::one< 0x20 > >( __LINE__, __FILE__, u16s_be( 0x20 ), result_type::success, 0 ); - verify_rule< utf16_be::one< 0x20ac > >( __LINE__, __FILE__, u16s_be( 0x20ac ), result_type::success, 0 ); - verify_rule< utf16_be::one< 0x10437 > >( __LINE__, __FILE__, u16s_be( 0xd801 ) + u16s_be( 0xdc37 ), result_type::success, 0 ); + verify_rule< utf16_be::one< 0x20 > >( __LINE__, __FILE__, u16s_be( 0x20 ), result_type::success ); + verify_rule< utf16_be::one< 0x20ac > >( __LINE__, __FILE__, u16s_be( 0x20ac ), result_type::success ); + verify_rule< utf16_be::one< 0x10437 > >( __LINE__, __FILE__, u16s_be( 0xd801 ) + u16s_be( 0xdc37 ), result_type::success ); - verify_rule< utf16_be::bom >( __LINE__, __FILE__, u16s_be( 0xfeff ), result_type::success, 0 ); - verify_rule< utf16_be::bom >( __LINE__, __FILE__, u16s_be( 0xfffe ), result_type::local_failure, 2 ); + verify_rule< utf16_be::bom >( __LINE__, __FILE__, u16s_be( 0xfeff ), result_type::success ); + verify_rule< utf16_be::bom >( __LINE__, __FILE__, u16s_be( 0xfffe ), result_type::local_failure ); verify_rule< utf16_be::string< 0x20, 0x20ac, 0x10437 > >( __LINE__, __FILE__, u16s_be( 0x20 ) + u16s_be( 0x20ac ) + u16s_be( 0xd801 ) + u16s_be( 0xdc37 ) + u16s_be( 0x20 ), result_type::success, 2 ); } void test_utf16_le() { - verify_rule< utf16_le::any >( __LINE__, __FILE__, "", result_type::local_failure, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, "\x01", result_type::local_failure, 1 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, "\xff", result_type::local_failure, 1 ); - - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0 ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 1 ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, " ", result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x00ff ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x0100 ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x0fff ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x1000 ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ), result_type::local_failure, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd900 ), result_type::local_failure, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xde00 ), result_type::local_failure, 0 ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, "", result_type::local_failure ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, "\x01", result_type::local_failure ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, "\xff", result_type::local_failure ); + + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0 ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 1 ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, " ", result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x00ff ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x0100 ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x0fff ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0x1000 ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ), result_type::local_failure ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd900 ), result_type::local_failure ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xde00 ), result_type::local_failure ); verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xfffe ) + " ", result_type::success, 1 ); verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xffff ) + " ", result_type::success, 2 ); verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd7ff ) + u16s_le( 0xdfff ), result_type::success, 2 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xdc00 ) + u16s_le( 0xdfff ), result_type::local_failure, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0x0020 ), result_type::local_failure, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0xff20 ), result_type::local_failure, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0xdf00 ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0xdfff ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xdbff ) + u16s_le( 0xdc00 ), result_type::success, 0 ); - verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xdbff ) + u16s_le( 0xdfff ), result_type::success, 0 ); - - verify_rule< utf16_le::one< 0x20 > >( __LINE__, __FILE__, u16s_le( 0x20 ), result_type::success, 0 ); - verify_rule< utf16_le::one< 0x20ac > >( __LINE__, __FILE__, u16s_le( 0x20ac ), result_type::success, 0 ); - verify_rule< utf16_le::one< 0x10437 > >( __LINE__, __FILE__, u16s_le( 0xd801 ) + u16s_le( 0xdc37 ), result_type::success, 0 ); - - verify_rule< utf16_le::bom >( __LINE__, __FILE__, u16s_le( 0xfeff ), result_type::success, 0 ); - verify_rule< utf16_le::bom >( __LINE__, __FILE__, u16s_le( 0xfffe ), result_type::local_failure, 2 ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xdc00 ) + u16s_le( 0xdfff ), result_type::local_failure ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0x0020 ), result_type::local_failure ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0xff20 ), result_type::local_failure ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0xdf00 ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xd800 ) + u16s_le( 0xdfff ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xdbff ) + u16s_le( 0xdc00 ), result_type::success ); + verify_rule< utf16_le::any >( __LINE__, __FILE__, u16s_le( 0xdbff ) + u16s_le( 0xdfff ), result_type::success ); + + verify_rule< utf16_le::one< 0x20 > >( __LINE__, __FILE__, u16s_le( 0x20 ), result_type::success ); + verify_rule< utf16_le::one< 0x20ac > >( __LINE__, __FILE__, u16s_le( 0x20ac ), result_type::success ); + verify_rule< utf16_le::one< 0x10437 > >( __LINE__, __FILE__, u16s_le( 0xd801 ) + u16s_le( 0xdc37 ), result_type::success ); + + verify_rule< utf16_le::bom >( __LINE__, __FILE__, u16s_le( 0xfeff ), result_type::success ); + verify_rule< utf16_le::bom >( __LINE__, __FILE__, u16s_le( 0xfffe ), result_type::local_failure ); verify_rule< utf16_le::string< 0x20, 0x20ac, 0x10437 > >( __LINE__, __FILE__, u16s_le( 0x20 ) + u16s_le( 0x20ac ) + u16s_le( 0xd801 ) + u16s_le( 0xdc37 ) + u16s_le( 0x20 ), result_type::success, 2 ); } diff --git a/packages/PEGTL/src/test/pegtl/utf32_general.cpp b/packages/PEGTL/src/test/pegtl/utf32_general.cpp index d00da771d978885e77ac582da9d0a6a80ea9f007..d9a435a2448923d5865fa64cda81d6965de7c31e 100644 --- a/packages/PEGTL/src/test/pegtl/utf32_general.cpp +++ b/packages/PEGTL/src/test/pegtl/utf32_general.cpp @@ -1,28 +1,30 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" #include "verify_rule.hpp" +#include <tao/pegtl/contrib/utf32.hpp> + namespace TAO_PEGTL_NAMESPACE { namespace { std::string u32s( const char32_t u ) { - return std::string( static_cast< const char* >( static_cast< const void* >( &u ) ), sizeof( u ) ); + return std::string( reinterpret_cast< const char* >( &u ), sizeof( u ) ); } std::string u32s_be( const char32_t v ) { const std::uint32_t u = internal::h_to_be( std::uint32_t( v ) ); - return std::string( static_cast< const char* >( static_cast< const void* >( &u ) ), sizeof( u ) ); + return std::string( reinterpret_cast< const char* >( &u ), sizeof( u ) ); } std::string u32s_le( const char32_t v ) { const std::uint32_t u = internal::h_to_le( std::uint32_t( v ) ); - return std::string( static_cast< const char* >( static_cast< const void* >( &u ) ), sizeof( u ) ); + return std::string( reinterpret_cast< const char* >( &u ), sizeof( u ) ); } } // namespace diff --git a/packages/PEGTL/src/test/pegtl/utf8_general.cpp b/packages/PEGTL/src/test/pegtl/utf8_general.cpp index fe0f85f415bb64d818e660be33bbad6125bd7f8a..6ac8b6631c611668d98ff5447cfa49f00971c5c5 100644 --- a/packages/PEGTL/src/test/pegtl/utf8_general.cpp +++ b/packages/PEGTL/src/test/pegtl/utf8_general.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include "test.hpp" diff --git a/packages/PEGTL/src/test/pegtl/verify_analyze.hpp b/packages/PEGTL/src/test/pegtl/verify_analyze.hpp index 4787e8aff703e485e050ac9b7f903968d5407cde..befefba5b6d8eaf5046aaf672db2719719507718 100644 --- a/packages/PEGTL/src/test/pegtl/verify_analyze.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_analyze.hpp @@ -1,10 +1,10 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_ANALYZE_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_ANALYZE_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_ANALYZE_HPP -#include <tao/pegtl/analyze.hpp> +#include <tao/pegtl/contrib/analyze.hpp> #include "test.hpp" @@ -13,7 +13,7 @@ namespace TAO_PEGTL_NAMESPACE template< typename Rule > void verify_analyze( const unsigned line, const char* file, const bool expect_consume, const bool expect_problems ) { - analysis::analyze_cycles< Rule > a( false ); + internal::analyze_cycles< Rule > a( false ); const bool has_problems = ( a.problems() != 0 ); const bool does_consume = a.template consumes< Rule >(); diff --git a/packages/PEGTL/src/test/pegtl/verify_char.hpp b/packages/PEGTL/src/test/pegtl/verify_char.hpp index 94800209d22e437fe9a78ae89c4478db015f42d2..3d2c4b793e8457d11ed1e4ce2a9fe679fc3478e4 100644 --- a/packages/PEGTL/src/test/pegtl/verify_char.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_char.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_CHAR_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_CHAR_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_CHAR_HPP #include <cstdlib> diff --git a/packages/PEGTL/src/test/pegtl/verify_fail.hpp b/packages/PEGTL/src/test/pegtl/verify_fail.hpp index 4ca68eec1a1459ace3f4b2a2154ef8fe7906f9c1..07269fdfbbdb3986e5585aaf8b346838bdc4fd98 100644 --- a/packages/PEGTL/src/test/pegtl/verify_fail.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_fail.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2015-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_FAIL_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_FAIL_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_FAIL_HPP #include <cstddef> diff --git a/packages/PEGTL/src/test/pegtl/verify_file.hpp b/packages/PEGTL/src/test/pegtl/verify_file.hpp index 3b3d4ad429fb42dd9efa83e772e55ffe380feb37..7ac5683c4444ece26b41c569e5f6c831d09bbb94 100644 --- a/packages/PEGTL/src/test/pegtl/verify_file.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_file.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_FILE_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_FILE_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_FILE_HPP #include <tao/pegtl.hpp> @@ -10,10 +10,12 @@ namespace TAO_PEGTL_NAMESPACE { - struct file_content : seq< TAO_PEGTL_STRING( "dummy content" ), eol, discard > + struct file_content + : seq< TAO_PEGTL_STRING( "dummy content" ), eol, discard > {}; - struct file_grammar : seq< rep_min_max< 11, 11, file_content >, eof > + struct file_grammar + : seq< rep_min_max< 11, 11, file_content >, eof > {}; template< typename Rule > @@ -38,8 +40,8 @@ namespace TAO_PEGTL_NAMESPACE struct file_control< eof > : normal< eof > { - template< typename Input > - static void success( const Input& /*unused*/, bool& flag ) + template< typename ParseInput > + static void success( const ParseInput& /*unused*/, bool& flag ) { flag = true; } diff --git a/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp b/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp index b7ea5e99c1130d1b4ce42c81e3234c8cd0799f1f..ac9368178f87a178b186d7fd68c8334a1d42c30f 100644 --- a/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_IFMT_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_IFMT_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_IFMT_HPP #include <tao/pegtl.hpp> diff --git a/packages/PEGTL/src/test/pegtl/verify_impl.hpp b/packages/PEGTL/src/test/pegtl/verify_impl.hpp index 59559840665bb6041b0015224f0a8816429211ba..83ad2977ca4f4d6abc0e540f594d7bbfbe026ff6 100644 --- a/packages/PEGTL/src/test/pegtl/verify_impl.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_impl.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_IMPL_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_IMPL_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_IMPL_HPP #include <cstddef> @@ -18,8 +18,8 @@ namespace TAO_PEGTL_NAMESPACE { - template< typename Rule, template< typename... > class Action, typename Input > - result_type verify_impl_two( Input& in ) + template< typename Rule, template< typename... > class Action, typename ParseInput > + result_type verify_impl_two( ParseInput& in ) { try { if( normal< Rule >::template match< apply_mode::action, rewind_mode::required, Action, normal >( in ) ) { @@ -36,8 +36,8 @@ namespace TAO_PEGTL_NAMESPACE } } - template< typename Rule, template< typename... > class Action, typename Input > - void verify_impl_one( const std::size_t line, const char* file, const std::string& data, Input& in, const result_type expected, const std::size_t remain ) + template< typename Rule, template< typename... > class Action, typename ParseInput > + void verify_impl_one( const std::size_t line, const char* file, const std::string& data, ParseInput& in, const result_type expected, const std::size_t remain ) { const result_type received = verify_impl_two< Rule, Action >( in ); diff --git a/packages/PEGTL/src/test/pegtl/verify_rule.hpp b/packages/PEGTL/src/test/pegtl/verify_rule.hpp index a6a8ef4a8ccc0981739278154d24cb757752746d..fc614e06da2d5a0711f804544a245833de4cd1d3 100644 --- a/packages/PEGTL/src/test/pegtl/verify_rule.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_rule.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_RULE_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_RULE_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_RULE_HPP #include <cstdlib> @@ -10,19 +10,26 @@ #include <tao/pegtl/eol.hpp> #include <tao/pegtl/memory_input.hpp> #include <tao/pegtl/tracking_mode.hpp> +#include <tao/pegtl/type_list.hpp> #include "result_type.hpp" #include "verify_impl.hpp" namespace TAO_PEGTL_NAMESPACE { + template< typename Name, typename Rule, typename... Rules > + void verify_meta() + { + static_assert( std::is_same_v< typename Name::rule_t, Rule > ); + static_assert( std::is_same_v< typename Name::subs_t, type_list< Rules... > > ); + } + template< typename Rule > struct verify_action_impl { - template< typename Input, typename... States > - static void apply( const Input& /*unused*/, States&&... /*unused*/ ) - { - } + template< typename ActionInput, typename... States > + static void apply( const ActionInput& /*unused*/, States&&... /*unused*/ ) + {} }; template< typename Rule > @@ -30,14 +37,15 @@ namespace TAO_PEGTL_NAMESPACE { template< typename... States > static void apply0( States&&... /*unused*/ ) - { - } + {} }; template< typename Rule, typename Eol = eol::lf_crlf > - void verify_rule( const std::size_t line, const char* file, const std::string& data, const result_type expected, std::size_t remain = 0 ) + void verify_rule( const std::size_t line, const char* file, const std::string& data, const result_type expected, int remain = -1 ) { - remain = ( expected == result_type::success ) ? remain : data.size(); + if( remain < 0 ) { + remain = ( expected == result_type::success ) ? 0 : int( data.size() ); + } { memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 0 ); verify_impl_one< Rule, nothing >( line, file, data, in, expected, remain ); diff --git a/packages/PEGTL/src/test/pegtl/verify_seqs.hpp b/packages/PEGTL/src/test/pegtl/verify_seqs.hpp index 1de8bcf445ccfca9fc10a52c8322334e4b958dd3..82d84b0e8bd026a56d2fb0d911f2e27e4ba10fa4 100644 --- a/packages/PEGTL/src/test/pegtl/verify_seqs.hpp +++ b/packages/PEGTL/src/test/pegtl/verify_seqs.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ -#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_SEQS_HPP // NOLINT +#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_SEQS_HPP #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_SEQS_HPP #include <tao/pegtl.hpp> diff --git a/packages/kokkos/.gitrepo b/packages/kokkos/.gitrepo index 25d2de3f21647f67c2e7b2c28678488d25372975..d9131b0c8b44b22749b5732ae9147f20d821d656 100644 --- a/packages/kokkos/.gitrepo +++ b/packages/kokkos/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = git@github.com:kokkos/kokkos.git branch = master - commit = 785d19f23ed4ba43354f9ecd7ef67cd5976ca4c8 - parent = 3c152cb1a42b2192c6ff4ad8066c29541f4dd721 + commit = 953d7968e8fc5908af954f883e2e38d02c279cf2 + parent = 55da1f845ac4f9ea049f2d6a97c7edef95a887ab cmdver = 0.4.1 method = merge diff --git a/packages/kokkos/CHANGELOG.md b/packages/kokkos/CHANGELOG.md index 149e63ca91c8b9b23afb3e78079c23c0dea5eb38..9595b03ff93066631fc1c8d32bb7ccaab04f4980 100644 --- a/packages/kokkos/CHANGELOG.md +++ b/packages/kokkos/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## [3.1.1](https://github.com/kokkos/kokkos/tree/3.1.1) (2020-04-14) +[Full Changelog](https://github.com/kokkos/kokkos/compare/3.1.00...3.1.1) + +**Fixed bugs:** + +- Fix complex_double misalignment in reduce, clang+CUDA [\#2989](https://github.com/kokkos/kokkos/issues/2989) +- Fix compilation fails when profiling disabled and CUDA enabled [\#3001](https://github.com/kokkos/kokkos/issues/3001) +- Fix cuda reduction of non-trivial scalars of size 4 [\#2990](https://github.com/kokkos/kokkos/issues/2990) +- Configure and install version file when building in Trilinos [\#2957](https://github.com/kokkos/kokkos/pull/2957) +- Fix OpenMPTarget build missing include and namespace [\#3000](https://github.com/kokkos/kokkos/issues/3000) +- fix typo in KOKKOS_SET_EXE_PROPERTY() [\#2959](https://github.com/kokkos/kokkos/issues/2959) +- Fix non-zero span subviews of zero sized subviews [\#2979](https://github.com/kokkos/kokkos/issues/2979) + ## [3.1.00](https://github.com/kokkos/kokkos/tree/3.1.00) (2020-04-14) [Full Changelog](https://github.com/kokkos/kokkos/compare/3.0.00...3.1.00) diff --git a/packages/kokkos/CMakeLists.txt b/packages/kokkos/CMakeLists.txt index db88879039603880fc76bce8e0d195fc60f675c8..0e2aaa1897074826ba672d0c6a5a4a0084a0f504 100644 --- a/packages/kokkos/CMakeLists.txt +++ b/packages/kokkos/CMakeLists.txt @@ -103,7 +103,7 @@ ENDIF() set(Kokkos_VERSION_MAJOR 3) set(Kokkos_VERSION_MINOR 1) -set(Kokkos_VERSION_PATCH 0) +set(Kokkos_VERSION_PATCH 1) set(Kokkos_VERSION "${Kokkos_VERSION_MAJOR}.${Kokkos_VERSION_MINOR}.${Kokkos_VERSION_PATCH}") math(EXPR KOKKOS_VERSION "${Kokkos_VERSION_MAJOR} * 10000 + ${Kokkos_VERSION_MINOR} * 100 + ${Kokkos_VERSION_PATCH}") diff --git a/packages/kokkos/Makefile.kokkos b/packages/kokkos/Makefile.kokkos index afb3a371e9cc471b696e00d363b8b66995bb166f..320d398d9494ff7c1f7148c3c47cfdbe6b1ca461 100644 --- a/packages/kokkos/Makefile.kokkos +++ b/packages/kokkos/Makefile.kokkos @@ -2,7 +2,7 @@ KOKKOS_VERSION_MAJOR = 3 KOKKOS_VERSION_MINOR = 1 -KOKKOS_VERSION_PATCH = 0 +KOKKOS_VERSION_PATCH = 1 KOKKOS_VERSION = $(shell echo $(KOKKOS_VERSION_MAJOR)*10000+$(KOKKOS_VERSION_MINOR)*100+$(KOKKOS_VERSION_PATCH) | bc) # Options: Cuda,HIP,ROCm,OpenMP,Pthread,Serial diff --git a/packages/kokkos/cmake/kokkos_install.cmake b/packages/kokkos/cmake/kokkos_install.cmake index 6a39590f036da00f133c0654cf99f0788d7e6075..97bb2bd0b052a31052d7ac3b947501a722ab0e5b 100644 --- a/packages/kokkos/cmake/kokkos_install.cmake +++ b/packages/kokkos/cmake/kokkos_install.cmake @@ -1,3 +1,4 @@ +INCLUDE(CMakePackageConfigHelpers) IF (NOT KOKKOS_HAS_TRILINOS) INCLUDE(GNUInstallDirs) @@ -11,7 +12,6 @@ IF (NOT KOKKOS_HAS_TRILINOS) "${Kokkos_BINARY_DIR}/KokkosConfig.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake) - INCLUDE(CMakePackageConfigHelpers) CONFIGURE_PACKAGE_CONFIG_FILE( cmake/KokkosConfigCommon.cmake.in "${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake" @@ -35,6 +35,13 @@ ELSE() CONFIGURE_FILE(cmake/KokkosTrilinosConfig.cmake.in ${Kokkos_BINARY_DIR}/KokkosTrilinosConfig.cmake @ONLY) file(READ ${Kokkos_BINARY_DIR}/KokkosTrilinosConfig.cmake KOKKOS_TRILINOS_CONFIG) file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/KokkosConfig_install.cmake" "${KOKKOS_TRILINOS_CONFIG}") + + WRITE_BASIC_PACKAGE_VERSION_FILE("${CMAKE_CURRENT_BINARY_DIR}/KokkosConfigVersion.cmake" + VERSION "${Kokkos_VERSION}" + COMPATIBILITY SameMajorVersion) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KokkosConfigVersion.cmake + DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PACKAGE_NAME}") ENDIF() INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/KokkosCore_config.h DESTINATION ${KOKKOS_HEADER_DIR}) diff --git a/packages/kokkos/cmake/kokkos_tribits.cmake b/packages/kokkos/cmake/kokkos_tribits.cmake index 1c3b704ada8eb8541694272ba88ed77c64302ba0..6ee1409aa72127d4ae4c127d097b4420a9149cb1 100644 --- a/packages/kokkos/cmake/kokkos_tribits.cmake +++ b/packages/kokkos/cmake/kokkos_tribits.cmake @@ -170,7 +170,7 @@ FUNCTION(KOKKOS_SET_EXE_PROPERTY ROOT_NAME) IF (NOT TARGET ${TARGET_NAME}) MESSAGE(SEND_ERROR "No target ${TARGET_NAME} exists - cannot set target properties") ENDIF() - SET_PROPERTY(TARGET ${TARGET_PROPERTY} PROPERTY ${ARGN}) + SET_PROPERTY(TARGET ${TARGET_NAME} PROPERTY ${ARGN}) ENDFUNCTION() MACRO(KOKKOS_SETUP_BUILD_ENVIRONMENT) diff --git a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp index 7d996fba0438e05c33ba0dbaf4831b21240429df..8795eb5a38b289c68768de4ddfa553307bb75152 100644 --- a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp +++ b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp @@ -97,7 +97,9 @@ __device__ inline // Depending on the ValueType _shared__ memory must be aligned up to 8byte // boundaries The reason not to use ValueType directly is that for types with // constructors it could lead to race conditions - __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; + alignas(alignof(ValueType) > alignof(double) ? alignof(ValueType) + : alignof(double)) + __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; ValueType* result = (ValueType*)&sh_result; const int step = 32 / blockDim.x; int shift = STEP_WIDTH; @@ -282,7 +284,9 @@ __device__ inline // Depending on the ValueType _shared__ memory must be aligned up to 8byte // boundaries The reason not to use ValueType directly is that for types with // constructors it could lead to race conditions - __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; + alignas(alignof(ValueType) > alignof(double) ? alignof(ValueType) + : alignof(double)) + __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; ValueType* result = (ValueType*)&sh_result; const int step = 32 / blockDim.x; int shift = STEP_WIDTH; diff --git a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp index f75d2e56f7ae687fc4b6345bc6c1762d1eb801e5..62966f859d1e88acfd96bf0949a6acfeac5ef89c 100644 --- a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp +++ b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp @@ -81,18 +81,19 @@ struct in_place_shfl_op { union conv_type { Scalar orig; shfl_type conv; + // This should be fine, members get explicitly reset, which changes the + // active member + KOKKOS_FUNCTION conv_type() { conv = 0; } }; conv_type tmp_in; tmp_in.orig = in; - conv_type tmp_out; - tmp_out.conv = tmp_in.conv; + shfl_type tmp_out; + tmp_out = reinterpret_cast<shfl_type&>(tmp_in.orig); conv_type res; //------------------------------------------------ - res.conv = self().do_shfl_op( - mask, reinterpret_cast<shfl_type const&>(tmp_out.conv), lane_or_delta, - width); + res.conv = self().do_shfl_op(mask, tmp_out, lane_or_delta, width); //------------------------------------------------ - out = res.orig; + out = reinterpret_cast<Scalar&>(res.conv); } // TODO: figure out why 64-bit shfl fails in Clang diff --git a/packages/kokkos/core/src/Kokkos_CudaSpace.hpp b/packages/kokkos/core/src/Kokkos_CudaSpace.hpp index 53e3b7778641d45af2d43b6fd08db499d012e370..7db5dd9561ece7679b7cf5b24bd381b143e7a6f9 100644 --- a/packages/kokkos/core/src/Kokkos_CudaSpace.hpp +++ b/packages/kokkos/core/src/Kokkos_CudaSpace.hpp @@ -56,6 +56,8 @@ #include <Kokkos_HostSpace.hpp> +#include <impl/Kokkos_Profiling_Interface.hpp> + #include <Cuda/Kokkos_Cuda_abort.hpp> #ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST diff --git a/packages/kokkos/core/src/Kokkos_OpenMPTarget.hpp b/packages/kokkos/core/src/Kokkos_OpenMPTarget.hpp index d113f244229ff81e95585a5043a65340846ea1d9..e853b8228d07364c45b28aa669feaef2c502dbdb 100644 --- a/packages/kokkos/core/src/Kokkos_OpenMPTarget.hpp +++ b/packages/kokkos/core/src/Kokkos_OpenMPTarget.hpp @@ -59,7 +59,7 @@ #include <Kokkos_TaskPolicy.hpp> #include <Kokkos_Layout.hpp> #include <impl/Kokkos_Tags.hpp> - +#include <impl/Kokkos_Profiling_Interface.hpp> #include <KokkosExp_MDRangePolicy.hpp> /*--------------------------------------------------------------------------*/ @@ -124,8 +124,9 @@ class OpenMPTarget { namespace Profiling { namespace Experimental { template <> -struct DeviceTypeTraits<Experimental::OpenMPTarget> { - static constexpr DeviceType id = DeviceType::OpenMPTarget; +struct DeviceTypeTraits<::Kokkos::Experimental::OpenMPTarget> { + static constexpr DeviceType id = + ::Kokkos::Profiling::Experimental::DeviceType::OpenMPTarget; }; } // namespace Experimental } // namespace Profiling diff --git a/packages/kokkos/core/src/impl/Kokkos_Core.cpp b/packages/kokkos/core/src/impl/Kokkos_Core.cpp index 9640e0fccb7595c884ace5a9097cbb09026400ce..6a6559e415dc15b44f881a0f60f37b739ddd7bb8 100644 --- a/packages/kokkos/core/src/impl/Kokkos_Core.cpp +++ b/packages/kokkos/core/src/impl/Kokkos_Core.cpp @@ -168,34 +168,7 @@ int get_ctest_gpu(const char* local_rank_str) { namespace { -bool is_unsigned_int(const char* str) { - const size_t len = strlen(str); - for (size_t i = 0; i < len; ++i) { - if (!isdigit(str[i])) { - return false; - } - } - return true; -} - -void initialize_backends(const InitArguments& args) { -// This is an experimental setting -// For KNL in Flat mode this variable should be set, so that -// memkind allocates high bandwidth memory correctly. -#ifdef KOKKOS_ENABLE_HBWSPACE - setenv("MEMKIND_HBW_NODES", "1", 0); -#endif - - // Protect declarations, to prevent "unused variable" warnings. -#if defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_THREADS) || \ - defined(KOKKOS_ENABLE_OPENMPTARGET) || defined(KOKKOS_ENABLE_HPX) - const int num_threads = args.num_threads; -#endif -#if defined(KOKKOS_ENABLE_THREADS) || defined(KOKKOS_ENABLE_OPENMPTARGET) - const int use_numa = args.num_numa; -#endif -#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_ROCM) || \ - defined(KOKKOS_ENABLE_HIP) +int get_gpu(const InitArguments& args) { int use_gpu = args.device_id; const int ndevices = args.ndevices; const int skip_device = args.skip_device; @@ -231,6 +204,38 @@ void initialize_backends(const InitArguments& args) { // shift assignments over by one so no one is assigned to "skip_device" if (use_gpu >= skip_device) ++use_gpu; } + return use_gpu; +} + +bool is_unsigned_int(const char* str) { + const size_t len = strlen(str); + for (size_t i = 0; i < len; ++i) { + if (!isdigit(str[i])) { + return false; + } + } + return true; +} + +void initialize_backends(const InitArguments& args) { +// This is an experimental setting +// For KNL in Flat mode this variable should be set, so that +// memkind allocates high bandwidth memory correctly. +#ifdef KOKKOS_ENABLE_HBWSPACE + setenv("MEMKIND_HBW_NODES", "1", 0); +#endif + + // Protect declarations, to prevent "unused variable" warnings. +#if defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_THREADS) || \ + defined(KOKKOS_ENABLE_OPENMPTARGET) || defined(KOKKOS_ENABLE_HPX) + const int num_threads = args.num_threads; +#endif +#if defined(KOKKOS_ENABLE_THREADS) || defined(KOKKOS_ENABLE_OPENMPTARGET) + const int use_numa = args.num_numa; +#endif +#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_ROCM) || \ + defined(KOKKOS_ENABLE_HIP) + int use_gpu = get_gpu(args); #endif // defined( KOKKOS_ENABLE_CUDA ) #if defined(KOKKOS_ENABLE_OPENMP) diff --git a/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp b/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp index a8dc1fb84a6fda5934b0bde58a4ac3f4d828fb90..c8230169e7ce873036d797251827e8e4d75db24b 100644 --- a/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp +++ b/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp @@ -1286,8 +1286,8 @@ struct ViewOffset< /* Span of the range space */ KOKKOS_INLINE_FUNCTION constexpr size_type span() const { - return m_stride * m_dim.N1 * m_dim.N2 * m_dim.N3 * m_dim.N4 * m_dim.N5 * - m_dim.N6 * m_dim.N7; + return (m_dim.N0 > size_type(0) ? m_stride : size_type(0)) * m_dim.N1 * + m_dim.N2 * m_dim.N3 * m_dim.N4 * m_dim.N5 * m_dim.N6 * m_dim.N7; } KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { @@ -1882,7 +1882,9 @@ struct ViewOffset< /* Span of the range space */ KOKKOS_INLINE_FUNCTION - constexpr size_type span() const { return m_dim.N0 * m_stride; } + constexpr size_type span() const { + return size() > 0 ? m_dim.N0 * m_stride : 0; + } KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { return m_stride == m_dim.N7 * m_dim.N6 * m_dim.N5 * m_dim.N4 * m_dim.N3 * @@ -2398,14 +2400,16 @@ struct ViewOffset<Dimension, Kokkos::LayoutStride, void> { /* Span of the range space, largest stride * dimension */ KOKKOS_INLINE_FUNCTION constexpr size_type span() const { - return Max(m_dim.N0 * m_stride.S0, - Max(m_dim.N1 * m_stride.S1, - Max(m_dim.N2 * m_stride.S2, - Max(m_dim.N3 * m_stride.S3, - Max(m_dim.N4 * m_stride.S4, - Max(m_dim.N5 * m_stride.S5, - Max(m_dim.N6 * m_stride.S6, - m_dim.N7 * m_stride.S7))))))); + return size() == size_type(0) + ? size_type(0) + : Max(m_dim.N0 * m_stride.S0, + Max(m_dim.N1 * m_stride.S1, + Max(m_dim.N2 * m_stride.S2, + Max(m_dim.N3 * m_stride.S3, + Max(m_dim.N4 * m_stride.S4, + Max(m_dim.N5 * m_stride.S5, + Max(m_dim.N6 * m_stride.S6, + m_dim.N7 * m_stride.S7))))))); } KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { diff --git a/packages/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp b/packages/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp index 33c736c5e01aa2b0e1b33a4b813749ee68ebd220..c27f13e956cef315d12c12607b0766eaa79f2738 100644 --- a/packages/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp +++ b/packages/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp @@ -273,7 +273,7 @@ void check_correct_initialization(const Kokkos::InitArguments& argstruct) { int expected_device = argstruct.device_id; if (argstruct.device_id < 0) { - expected_device = 0; + expected_device = Kokkos::Cuda().cuda_device(); } ASSERT_EQ(expected_device, device); diff --git a/packages/kokkos/master_history.txt b/packages/kokkos/master_history.txt index f6eb95292c2ebce443d7350155e059f6686d433a..11e803e76026ef9be546255ef1c5406972ca07c4 100644 --- a/packages/kokkos/master_history.txt +++ b/packages/kokkos/master_history.txt @@ -19,3 +19,4 @@ tag: 2.8.00 date: 02:05:2019 master: 34931a36 develop: d1659d1d tag: 2.9.00 date: 06:24:2019 master: 5d6e7fb3 develop: 4c6cb80a tag: 3.0.00 date: 01:31:2020 master: 2983b80d release-candidate-3.0: fdc904a6 tag: 3.1.00 date: 04:14:2020 master: cd1b1d0a develop: fd90af43 +tag: 3.1.1 date: 05:04:2020 master: 785d19f2 release: 2be028bc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42d75ad7e7146554812cef242214d290903d8f31..0d6e8cbb996d4f6c18c9098bb9af7051c11b0dbf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,8 +15,5 @@ add_subdirectory(language) # Pugs mesh add_subdirectory(mesh) -# Pugs mesh -#add_subdirectory(mesh) - # Pugs output #add_subdirectory(output) diff --git a/src/algebra/TinyVector.hpp b/src/algebra/TinyVector.hpp index 5f5e8a7eb109ba293e13eb9a153918c126816923..07690a826ef13040e42baca75daac425fa199333 100644 --- a/src/algebra/TinyVector.hpp +++ b/src/algebra/TinyVector.hpp @@ -14,7 +14,8 @@ template <size_t N, typename T = double> class TinyVector { public: - using data_type = T; + inline static constexpr size_t Dimension = N; + using data_type = T; private: T m_values[N]; diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt index b01587e455a481b01f44db34cd7dd8d75adcb59e..b9c6094e4403cb1d2289d8cfcae58de9e2e3c4e5 100644 --- a/src/language/CMakeLists.txt +++ b/src/language/CMakeLists.txt @@ -1,11 +1,21 @@ # ------------------- Source files -------------------- +add_subdirectory(ast) +add_subdirectory(modules) +add_subdirectory(node_processor) +add_subdirectory(utils) + add_library( PugsLanguage PugsParser.cpp) # Additional dependencies -#add_dependencies(PugsMesh) +add_dependencies(PugsLanguage + PugsLanguage + PugsLanguageAST + PugsLanguageModules + PugsLanguageUtils + PugsUtils) # ------------------- Installation -------------------- # temporary version workaround diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp new file mode 100644 index 0000000000000000000000000000000000000000..336fb5583fb4e163f37feb30956acbf27cef36ab --- /dev/null +++ b/src/language/PEGGrammar.hpp @@ -0,0 +1,397 @@ +#ifndef PEG_GRAMMAR_HPP +#define PEG_GRAMMAR_HPP + +#include <pegtl.hpp> + +using namespace TAO_PEGTL_NAMESPACE; + +namespace language +{ +// clang-format off + +struct slashslash : TAO_PEGTL_STRING("//") {}; +struct slashstar : TAO_PEGTL_STRING("/*") {}; +struct starslash : TAO_PEGTL_STRING("*/") {}; + +struct comment + : sor< if_must< slashslash, until< eolf > >, + try_catch< slashstar, until< starslash> >, + // error management + if_must<at<slashstar>,raise<slashstar>, until< eof> > > {}; + +struct ignored : star< sor< space, comment> >{}; + +struct integer + : plus< digit > {}; +struct INTEGER : seq< integer, ignored >{}; + +struct exponent + : seq< one< 'E', 'e' >, + opt< one< '+', '-' > >, + plus<digit> + >{}; + +struct real + : sor< seq< sor< seq< + plus< digit >, + one < '.' >, + star< digit > + >, + seq< + one < '.' >, + plus< digit > + > + >, + opt< exponent > + >, + seq< plus< digit, exponent > > + >{}; + +struct escaped_c : one< '\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v' > {}; +struct character : if_must_else< one< '\\' >, escaped_c, ascii::any> {}; + +struct open_parent : seq< one< '(' >, ignored > {}; +struct close_parent : seq< one< ')' >, ignored > {}; + +struct literal : if_must< one< '"' >, until< one< '"' >, character > > {}; + +struct import_kw : TAO_PEGTL_KEYWORD("import") {}; + +struct LITERAL : seq< literal, ignored >{}; + +struct REAL : seq< real, ignored >{}; + +struct B_set : TAO_PEGTL_KEYWORD("B"){}; +struct N_set : TAO_PEGTL_KEYWORD("N"){}; +struct Z_set : TAO_PEGTL_KEYWORD("Z"){}; +struct R_set : TAO_PEGTL_KEYWORD("R"){}; + +struct string_type : TAO_PEGTL_KEYWORD("string") {}; + +struct scalar_type : sor< B_set, R_set, Z_set, N_set >{}; + +struct vector_type : seq< R_set, ignored, one< '^' >, ignored, integer >{}; + +struct basic_type : sor< scalar_type, string_type >{}; + +struct type_name_id; +struct simple_type_specifier : sor< vector_type, basic_type, type_name_id >{}; + +struct tuple_type_specifier : sor<try_catch< open_parent, simple_type_specifier, ignored, close_parent >, + // non matching braces management + if_must< at< open_parent >, raise< simple_type_specifier >, until< eof > > >{}; + +struct TYPE_SPECIFIER : seq< sor<simple_type_specifier, tuple_type_specifier>, ignored >{}; + +struct type_expression : list_must< TYPE_SPECIFIER, seq< ignored, one< '*' >, ignored > >{}; +struct TYPE_EXPRESSION : seq< type_expression, ignored >{}; + +struct and_kw : TAO_PEGTL_KEYWORD("and") {}; +struct or_kw : TAO_PEGTL_KEYWORD("or") {}; + +struct xor_kw : TAO_PEGTL_KEYWORD("xor") {}; + +struct not_kw : TAO_PEGTL_KEYWORD("not") {}; +struct true_kw : TAO_PEGTL_KEYWORD("true") {}; +struct false_kw : TAO_PEGTL_KEYWORD("false") {}; + +struct BOOL : seq< sor< true_kw, false_kw >, ignored > {}; + +struct let_kw : TAO_PEGTL_KEYWORD("let") {}; +struct LET : seq < let_kw, ignored > {}; + +struct do_kw : TAO_PEGTL_KEYWORD("do") {}; +struct DO : seq < do_kw, ignored > {}; + +struct while_kw : TAO_PEGTL_KEYWORD("while") {}; +struct WHILE : seq < while_kw, ignored > {}; + +struct for_kw : TAO_PEGTL_KEYWORD("for") {}; +struct FOR : seq < for_kw, ignored > {}; + +struct if_kw : TAO_PEGTL_KEYWORD("if") {}; +struct IF : seq < if_kw, ignored > {}; + +struct else_kw : TAO_PEGTL_KEYWORD("else") {}; +struct ELSE : seq < else_kw, ignored > {}; + +struct break_kw : TAO_PEGTL_KEYWORD("break") {}; +struct BREAK : seq < break_kw, ignored > {}; + +struct continue_kw : TAO_PEGTL_KEYWORD("continue") {}; +struct CONTINUE : seq < continue_kw, ignored > {}; + +struct cout_kw : TAO_PEGTL_KEYWORD("cout") {}; +struct cerr_kw : TAO_PEGTL_KEYWORD("cerr") {}; +struct clog_kw : TAO_PEGTL_KEYWORD("clog") {}; + +struct keyword : sor < basic_type, import_kw, true_kw, false_kw, let_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, not_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {}; + +struct identifier_minus_keyword : minus< identifier, keyword > {}; + +struct module_name : identifier_minus_keyword {}; +struct MODULE_NAME : seq< module_name, ignored > {}; + +struct type_name_id : identifier_minus_keyword {}; + +struct name : identifier_minus_keyword {}; +struct NAME : seq< name, ignored > {}; + +struct right_arrow_kw : seq< one< '-' >, one< '>' > > {}; +struct RIGHT_ARROW : seq< right_arrow_kw, ignored > {}; + +struct semicol : one< ';' > {}; +struct SEMICOL : seq< semicol , ignored > {}; + +struct column : one< ':' > {}; +struct COLUMN : seq< column , ignored > {}; + +struct comma : one< ',' > {}; +struct COMMA : seq< comma , ignored > {}; + +struct expression; +struct parented_expression : if_must< open_parent, expression, close_parent >{}; + +struct tuple_expression; +struct function_argument_list : if_must< open_parent, opt< list_must< sor< tuple_expression, expression >, COMMA > >, close_parent >{}; +struct function_evaluation : seq< NAME, function_argument_list > {}; + +struct primary_expression : sor< BOOL, REAL, INTEGER, LITERAL, function_evaluation, NAME, parented_expression > {}; + +struct unary_plusplus : TAO_PEGTL_STRING("++") {}; +struct unary_minusminus : TAO_PEGTL_STRING("--") {}; + +struct unary_plus : one< '+' > {}; +struct unary_minus : one< '-' > {}; + +struct unary_not : not_kw {}; + +struct unary_operator : seq< sor< unary_plusplus, unary_minusminus, unary_plus, unary_minus, unary_not>, ignored > {}; + +struct post_plusplus : TAO_PEGTL_STRING("++") {}; +struct post_minusminus : TAO_PEGTL_STRING("--") {}; + +struct postfix_operator : seq< sor< post_plusplus, post_minusminus>, ignored > {}; + +struct open_bracket : seq< one< '[' >, ignored > {}; +struct close_bracket : seq< one< ']' >, ignored > {}; + +struct subscript_expression : if_must< open_bracket, expression, close_bracket >{}; + +struct postfix_expression : seq< primary_expression, star< sor< subscript_expression , postfix_operator> > >{}; + +struct unary_expression : sor< seq< unary_operator, unary_expression >, + postfix_expression > {}; + +struct and_op : seq< and_kw, ignored > {}; +struct or_op : seq< or_kw, ignored > {}; +struct xor_op : seq< xor_kw, ignored >{}; + +struct eqeq_op : seq< TAO_PEGTL_STRING("=="), ignored > {}; +struct not_eq_op : seq< TAO_PEGTL_STRING("!="), ignored > {}; + +struct lesser_op : seq< one< '<' >, not_at< one< '<' > >, ignored > {}; +struct lesser_or_eq_op : seq< TAO_PEGTL_STRING("<="), ignored > {}; +struct greater_op : seq< one< '>' >, not_at< one< '>' > >, ignored > {}; +struct greater_or_eq_op : seq< TAO_PEGTL_STRING(">="), ignored > {}; + +struct shift_left_op : seq< TAO_PEGTL_STRING("<<"), ignored > {}; +struct shift_right_op : seq< TAO_PEGTL_STRING(">>"), ignored > {}; + +struct plus_op : seq< one< '+' >, not_at< one< '+' > >, ignored > {}; +struct minus_op : seq< one< '-' >, not_at< one< '-' > >, ignored > {}; +struct multiply_op : seq< one< '*' >, ignored > {}; +struct divide_op : seq< one< '/' >, ignored > {}; + +struct eq_op : seq< one<'='>, not_at< one< '=' > >, ignored > {}; +struct multiplyeq_op : seq< TAO_PEGTL_STRING("*="), ignored > {}; +struct divideeq_op : seq< TAO_PEGTL_STRING("/="), ignored > {}; +struct pluseq_op : seq< TAO_PEGTL_STRING("+="), ignored > {}; +struct minuseq_op : seq< TAO_PEGTL_STRING("-="), ignored > {}; + +struct product : list_must< unary_expression, sor< multiply_op, divide_op > > {}; + +struct sum : list_must< product, sor< plus_op, minus_op > > {}; + +struct compare : list_must<sum, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{}; + +struct equality : list_must< compare, sor< eqeq_op, not_eq_op > >{}; + +struct bitwise_xor : list_must< equality, xor_op >{}; + +struct logical_and : list_must< bitwise_xor, and_op >{}; + +struct logical_or : list_must< logical_and, or_op >{}; + +struct expression : logical_or {}; + +struct tuple_expression : seq< open_parent, expression, plus< if_must< COMMA, expression > >, close_parent >{}; + +struct expression_list : seq< open_parent, sor< tuple_expression, expression >, plus< if_must< COMMA, sor< tuple_expression, expression > > >, close_parent >{}; + +struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op > {}; + +struct name_subscript_expression : seq< NAME, plus< subscript_expression > >{}; + +struct lvalue_expression : sor< name_subscript_expression, NAME >{}; + +struct lvalue_list : seq< open_parent, list_must< lvalue_expression, COMMA >, close_parent >{}; + +struct affectation : seq< sor< lvalue_expression, lvalue_list >, if_must< affect_op, sor< expression_list, expression > > >{}; + +struct name_list; + +struct var_definition : seq< sor< NAME, name_list>, one< '=' >, ignored, sor< expression_list, expression > >{}; + +struct var_declaration : seq< LET, sor< NAME, name_list>, COLUMN, TYPE_EXPRESSION, opt< if_must< COMMA, var_definition > > >{}; + +struct type_mapping : seq< TYPE_EXPRESSION, RIGHT_ARROW, TYPE_EXPRESSION >{}; + +struct name_list : seq< open_parent, list_must< NAME, COMMA >, close_parent >{}; + +struct function_definition : seq< sor< name_list, NAME >, RIGHT_ARROW, sor< expression_list, expression > >{}; + +struct fct_declaration : seq< LET, NAME, COLUMN, type_mapping, COMMA, function_definition >{}; + +struct open_brace : seq< one< '{' >, ignored >{}; +struct close_brace : seq< one< '}' >, ignored >{}; + +struct instruction_list; + +struct braced_instruction_list + : sor<try_catch< open_brace, instruction_list, close_brace >, + // non matching braces management + if_must< at< one< '{' > >, raise< open_brace >, until< eof > > >{}; + +struct block : braced_instruction_list {}; + +struct statement_block; + +struct if_statement : if_must< IF, parented_expression, statement_block, opt< if_must<ELSE, statement_block > > >{}; + +struct do_while_statement : if_must< DO, statement_block, WHILE, parented_expression >{}; + +struct while_statement : if_must< WHILE, parented_expression, statement_block >{}; + +struct for_init : opt< sor< var_declaration, affectation, expression > >{}; +struct for_test : opt< sor< affectation, expression > >{}; +struct for_post : opt< sor< affectation, expression > >{}; + +struct for_statement_block; + +struct for_statement : if_must< FOR, open_parent, for_init, SEMICOL, for_test, SEMICOL, for_post, close_parent, for_statement_block >{}; + +struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{}; +struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{}; + +struct instruction + : sor<if_statement, + if_must<do_while_statement, semicol>, + while_statement, + for_statement, + if_must< ostream_statement, semicol >, + if_must< BREAK, semicol >, + if_must< CONTINUE, semicol >, + block, + if_must< fct_declaration, semicol >, + if_must< var_declaration, semicol >, + if_must< affectation, semicol >, + if_must< expression, semicol >, + semicol> +{}; + +struct INSTRUCTION : seq<instruction, ignored> {}; +struct statement_block : seq< sor< block, instruction >, ignored >{}; + +struct for_statement_block : seq< sor< braced_instruction_list, + instruction >, + ignored >{}; + +struct IMPORT : seq< import_kw, ignored >{}; + +struct import_instruction : if_must< IMPORT, MODULE_NAME , semicol >{}; +struct IMPORT_INSTRUCTION : seq<import_instruction, ignored> {}; +struct import_list : star< IMPORT_INSTRUCTION > {}; + +struct instruction_list : star< INSTRUCTION >{}; +struct grammar : must<ignored, import_list, instruction_list, eof>{}; + +template <typename Rule> +struct errors : public normal<Rule> +{ + static const std::string error_message; + + template <typename Input, typename... States> + static void + raise(const Input& in, States&&... /*unused*/) + { + throw parse_error(error_message, std::vector{in.position()}); + } +}; + +template <typename Rule> +inline const std::string errors<Rule>::error_message = "parse error matching "+ demangle(internal::demangle< Rule >()); + +template <> +inline const std::string errors<language::module_name>::error_message = "parse error, missing module name"; +template <> +inline const std::string errors<language::MODULE_NAME>::error_message = "parse error, missing module name"; + +template <> +inline const std::string errors<language::semicol>::error_message = "parse error, missing ';'"; +template <> +inline const std::string errors<language::SEMICOL>::error_message = "parse error, missing ';'"; + +template <> +inline const std::string errors<language::name>::error_message = "parse error, missing identifier"; +template <> +inline const std::string errors<language::NAME>::error_message = "parse error, missing identifier"; + +template <> +inline const std::string errors<language::expression>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::product>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::sum>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::compare>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::equality>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::bitwise_xor>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::logical_and>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::logical_or>::error_message = "parse error, missing expression"; + +template <> +inline const std::string errors<language::parented_expression>::error_message = "parse error, missing parented expression"; + +template <> +inline const std::string errors<language::statement_block>::error_message = "parse error, missing instruction"; + +template <> +inline const std::string errors<language::WHILE>::error_message = "parse error, missing 'while' statement"; +template <> +inline const std::string errors<language::while_kw>::error_message = "parse error, missing 'while' statement"; + +template <> +inline const std::string errors<language::open_parent>::error_message = "parse error, missing open parent '('"; + +template <> +inline const std::string errors<language::for_statement_block>::error_message = "parse error, missing for-loop body"; + +template <> +inline const std::string errors<language::slashstar>::error_message = "block comment was never terminated, missing '*/'"; + +template <> +inline const std::string errors<language::open_brace>::error_message = "open brace was never closed, missing '}'"; + +template <> +inline const std::string errors<language::simple_type_specifier>::error_message = "expecting simple type specifier"; + +// clang-format on + +} // namespace language + +#endif // PEG_GRAMMAR_HPP diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index a413c3fa7f733c47ff64d2b36be97c534b923d5c..235eab368dccfd2c41dde312a6f24264388a7813 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -1,185 +1,109 @@ #include <language/PugsParser.hpp> -#include <rang.hpp> +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDataTypeChecker.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeEmptyBlockCleaner.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeJumpPlacementChecker.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolInitializationChecker.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTDotPrinter.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsUtils.hpp> +#include <utils/SignalManager.hpp> + +#include <pegtl/contrib/analyze.hpp> +#include <pegtl/contrib/parse_tree.hpp> +#include <pegtl/contrib/parse_tree_to_dot.hpp> -#include <pegtl.hpp> -#include <pegtl/analyze.hpp> +#include <rang.hpp> +#include <fstream> #include <iostream> +#include <sstream> +#include <unordered_map> +#include <variant> -using namespace TAO_PEGTL_NAMESPACE; - -namespace language -{ -// clang-format off - -struct comment - : sor< if_must< - string< '/', '/' >, - until< eolf > - >, - if_must< - string< '/', '*' >, - until< string< '*', '/' > > - > - > {}; - -struct ignored - : star< sor< space, comment> >{}; - -// struct ignored : star< space >{}; - -struct integer - : seq< opt< one< '+', '-' > >, plus< digit > >{}; -struct INTEGER : seq< integer, ignored >{}; - -struct real - : seq< opt< one< '+', - '-' > - >, - sor< seq< - plus< digit >, - one < '.' >, - star< digit > - >, - seq< - one < '.' >, - plus< digit > - > - >, - opt< - seq< - one< 'E', - 'e' >, - opt< one< '+', - '-' > - >, - plus<digit> - > - > - >{}; - -struct REAL : seq< real, ignored >{}; - -struct IDENTIFIER : seq <identifier, ignored> {}; - -struct expression : sor< REAL, INTEGER , IDENTIFIER> {}; - -struct EXPRESSION : seq< expression, ignored> {}; - -struct binary_op - : seq< EXPRESSION , one< '+' >, EXPRESSION> {}; - -struct semicol : one< ';' >{}; -struct SEMICOL : seq< semicol , ignored > {}; - -struct instruction - : sor<seq< expression , SEMICOL >, - seq< binary_op, SEMICOL >, - SEMICOL> -{}; - -struct grammar - : must<ignored, star<instruction>,eof>{}; -// clang-format on - -template <typename Rule> -struct action : nothing<Rule> +void +parser(const std::string& filename) { -}; + const size_t grammar_issues = analyze<language::grammar>(); -template <> -struct action<integer> -{ - template <typename Input> - static void - apply(const Input& in, std::string& v) - { - v += std::string("I:") + in.string() + std::string(" ;\n"); - } -}; + std::cout << rang::fgB::yellow << "grammar_issues=" << rang::fg::reset << grammar_issues << '\n'; -template <> -struct action<real> -{ - template <typename Input> - static void - apply(const Input& in, std::string& v) - { - v += std::string("R:") + in.string() + std::string(" ;\n"); - } -}; + std::cout << rang::style::bold << "Parsing file " << rang::style::reset << rang::style::underline << filename + << rang::style::reset << " ...\n"; -template <> -struct action<identifier> -{ - template <typename Input> - static void - apply(const Input& in, std::string& v) - { - v += std::string("S:") + in.string() + std::string(" ;\n"); - } -}; + auto parse_and_execute = [](auto& input) { + std::unique_ptr<ASTNode> root_node = ASTBuilder::build(input); -template <> -struct action<binary_op> -{ - template <typename Input> - static void - apply(const Input& in, std::string& v) - { - v += "binary_op(" + in.string() + std::string(") ;\n"); - } -}; + ASTModulesImporter{*root_node}; + ASTNodeTypeCleaner<language::import_instruction>{*root_node}; -template <typename Rule> -struct errors : public normal<Rule> -{ - static const std::string error_message; + ASTSymbolTableBuilder{*root_node}; - template <typename Input, typename... States> - static void - raise(const Input& in, States&&... /*unused*/) - { - throw parse_error(error_message, std::vector{in.position()}); - } -}; + ASTSymbolInitializationChecker{*root_node}; -template <typename Rule> -const std::string errors<Rule>::error_message = "parse error..."; + ASTNodeDataTypeBuilder{*root_node}; -template <> -const std::string errors<eolf>::error_message = "parse error expecting expression"; + ASTNodeDataTypeChecker{*root_node}; -} // namespace language + ASTNodeJumpPlacementChecker{*root_node}; -void -parser(const std::string& filename) -{ - std::string name; + // optimizations + ASTNodeDeclarationToAffectationConverter{*root_node}; - const size_t grammar_issues = analyze<language::grammar>(); + ASTNodeTypeCleaner<language::var_declaration>{*root_node}; + ASTNodeTypeCleaner<language::fct_declaration>{*root_node}; - std::cout << rang::fgB::yellow << "grammar_issues=" << rang::fg::reset << grammar_issues << '\n'; + { + std::string dot_filename{"parse_tree.dot"}; + std::ofstream fout(dot_filename); + ASTDotPrinter dot_printer{*root_node}; + fout << dot_printer; + std::cout << " AST dot file: " << dot_filename << '\n'; + } - std::cout << rang::style::bold << "Parsing file " << rang::style::reset << rang::style::underline << filename - << rang::style::reset << " ...\n\n"; + ASTNodeEmptyBlockCleaner{*root_node}; - read_input in(filename); - try { - parse<language::grammar, - language::action //, language::errors - >(in, name); - } - catch (const parse_error& e) { - const auto p = e.positions.front(); - std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.byte_in_line << ": " << rang::style::reset - << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << e.what() << rang::style::reset - << '\n' - << in.line_at(p) << '\n' - << std::string(p.byte_in_line, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << std::endl; - std::exit(1); - } + ASTNodeExpressionBuilder{*root_node}; + + std::cout << ASTPrinter{*root_node} << '\n'; - std::cout << "Parsed:\n" << name << std::endl; + ExecutionPolicy exec_all; + root_node->execute(exec_all); + std::cout << *(root_node->m_symbol_table) << '\n'; + + root_node->m_symbol_table->clearValues(); + }; + + if (not SignalManager::pauseOnError()) { + read_input input(filename); + try { + parse_and_execute(input); + } + catch (const parse_error& e) { + const auto p = e.positions.front(); + + std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.byte_in_line << ": " << rang::style::reset + << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << e.what() << rang::style::reset + << '\n' + << input.line_at(p) << '\n' + << std::string(p.byte_in_line, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << '\n'; + finalize(); + std::exit(1); + } + } else { + read_input input(filename); + parse_and_execute(input); + } + std::cout << "Executed successfuly: " << filename << '\n'; } diff --git a/src/language/ast/ASTBuilder.cpp b/src/language/ast/ASTBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cef779ffce63b9c2ad808ca94b993e7eff59d4ff --- /dev/null +++ b/src/language/ast/ASTBuilder.cpp @@ -0,0 +1,329 @@ +#include <language/ast/ASTBuilder.hpp> + +using namespace TAO_PEGTL_NAMESPACE; + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/PugsAssert.hpp> + +#include <pegtl/contrib/parse_tree.hpp> + +struct ASTBuilder::rearrange : parse_tree::apply<ASTBuilder::rearrange> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&... st) + { + if (n->children.size() == 1) { + n = std::move(n->children.back()); + } else { + // First we rearrange tree + { + auto& children = n->children; + auto rhs = std::move(children.back()); + children.pop_back(); + auto op = std::move(children.back()); + children.pop_back(); + op->children.emplace_back(std::move(n)); + op->children.emplace_back(std::move(rhs)); + n = std::move(op); + transform(n->children.front(), st...); + } + // Then we eventually simplify operations + { + if (n->is_type<language::minus_op>()) { + Assert(n->children.size() == 2); + auto& rhs = n->children[1]; + if (rhs->is_type<language::unary_minus>()) { + n->set_type<language::plus_op>(); + rhs = std::move(rhs->children[0]); + } + } else if (n->is_type<language::plus_op>()) { + Assert(n->children.size() == 2); + auto& rhs = n->children[1]; + if (rhs->is_type<language::unary_minus>()) { + n->set_type<language::minus_op>(); + rhs = std::move(rhs->children[0]); + } + } + } + } + } +}; + +struct ASTBuilder::simplify_unary : parse_tree::apply<ASTBuilder::simplify_unary> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&... st) + { + if (n->children.size() == 1) { + if (n->is_type<language::unary_expression>() or n->is_type<language::type_expression>() or + n->is_type<language::name_subscript_expression>()) { + n = std::move(n->children.back()); + transform(n, st...); + } else if (n->is_type<language::unary_minus>()) { + auto& child = n->children[0]; + if (child->is_type<language::unary_minus>()) { + n = std::move(child->children[0]); + transform(n, st...); + } + } else if (n->is_type<language::unary_not>()) { + auto& child = n->children[0]; + if (child->is_type<language::unary_not>()) { + n = std::move(child->children[0]); + transform(n, st...); + } + } + } else if (n->children.size() == 2) { + if (n->children[0]->is_type<language::unary_plus>()) { + n = std::move(n->children[1]); + transform(n, st...); + } else if (n->children[0]->is_type<language::unary_minus>() or n->children[0]->is_type<language::unary_not>() or + n->children[0]->is_type<language::unary_minusminus>() or + n->children[0]->is_type<language::unary_plusplus>()) { + auto expression = std::move(n->children[1]); + auto unary_operator = std::move(n->children[0]); + unary_operator->children.emplace_back(std::move(expression)); + n = std::move(unary_operator); + transform(n, st...); + } + } + + if (n->is_type<language::unary_expression>()) { + const size_t child_nb = n->children.size(); + if (child_nb > 1) { + if (n->children[child_nb - 1]->is_type<language::post_minusminus>() or + n->children[child_nb - 1]->is_type<language::post_plusplus>()) { + auto unary_operator = std::move(n->children[child_nb - 1]); + n->children.pop_back(); + + unary_operator->children.emplace_back(std::move(n)); + + n = std::move(unary_operator); + transform(n->children[0], st...); + } + } + } + + if (n->is_type<language::unary_expression>() or n->is_type<language::name_subscript_expression>()) { + const size_t child_nb = n->children.size(); + if (child_nb > 1) { + if (n->children[1]->is_type<language::subscript_expression>()) { + auto expression = std::move(n->children[0]); + for (size_t i = 0; i < child_nb - 1; ++i) { + n->children[i] = std::move(n->children[i + 1]); + } + + auto& array_subscript_expression = n->children[0]; + n->children.pop_back(); + array_subscript_expression->children.emplace_back(std::move(expression)); + + std::swap(array_subscript_expression->children[0], array_subscript_expression->children[1]); + + array_subscript_expression->m_begin = array_subscript_expression->children[0]->m_begin; + + transform(n, st...); + } + } + } + } +}; + +struct ASTBuilder::simplify_node_list : parse_tree::apply<ASTBuilder::simplify_node_list> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&... st) + { + if (n->is_type<language::name_list>() or n->is_type<language::lvalue_list>() or + n->is_type<language::function_argument_list>() or n->is_type<language::expression_list>()) { + if (n->children.size() == 1) { + n = std::move(n->children.back()); + transform(n, st...); + } + } + } +}; + +struct ASTBuilder::simplify_statement_block : parse_tree::apply<ASTBuilder::simplify_statement_block> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&... st) + { + if ((n->is_type<language::statement_block>() or n->is_type<language::block>()) and (n->children.size() == 1)) { + if (not n->children[0]->is_type<language::var_declaration>()) { + n = std::move(n->children.back()); + transform(n, st...); + } else { + n->set_type<language::block>(); + } + } + } +}; + +struct ASTBuilder::simplify_for_statement_block : parse_tree::apply<ASTBuilder::simplify_for_statement_block> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&... st) + { + if ((n->is_type<language::for_statement_block>() or n->is_type<language::block>()) and (n->children.size() == 1)) { + n = std::move(n->children.back()); + transform(n, st...); + } + } +}; + +struct ASTBuilder::simplify_for_init : parse_tree::apply<ASTBuilder::simplify_for_init> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&...) + { + Assert(n->children.size() <= 1); + if (n->children.size() == 1) { + n = std::move(n->children.back()); + } + } +}; + +struct ASTBuilder::simplify_for_test : parse_tree::apply<ASTBuilder::simplify_for_test> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&...) + { + Assert(n->children.size() <= 1); + if (n->children.size() == 1) { + n = std::move(n->children.back()); + } + } +}; + +struct ASTBuilder::simplify_for_post : parse_tree::apply<ASTBuilder::simplify_for_post> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&...) + { + Assert(n->children.size() <= 1); + if (n->children.size() == 1) { + n = std::move(n->children.back()); + } + } +}; + +struct ASTBuilder::simplify_stream_statement : parse_tree::apply<ASTBuilder::simplify_stream_statement> +{ + template <typename... States> + static void + transform(std::unique_ptr<ASTNode>& n, States&&...) + { + for (size_t i = 1; i < n->children.size(); ++i) { + n->children[0]->children.emplace_back(std::move(n->children[i])); + } + n = std::move(n->children[0]); + } +}; + +template <typename Rule> +using selector = parse_tree::selector< + Rule, + parse_tree::store_content::on<language::import_instruction, + language::module_name, + language::true_kw, + language::false_kw, + language::integer, + language::real, + language::literal, + language::name, + language::B_set, + language::N_set, + language::Z_set, + language::R_set, + language::type_name_id, + language::tuple_expression, + language::vector_type, + language::string_type, + language::cout_kw, + language::cerr_kw, + language::clog_kw, + language::var_declaration, + language::fct_declaration, + language::type_mapping, + language::function_definition, + language::if_statement, + language::do_while_statement, + language::while_statement, + language::for_statement, + language::function_evaluation, + language::break_kw, + language::continue_kw>, + ASTBuilder::rearrange::on<language::logical_or, + language::logical_and, + language::bitwise_xor, + language::equality, + language::compare, + language::sum, + language::product, + language::affectation, + language::expression>, + ASTBuilder::simplify_unary::on<language::unary_minus, + language::unary_plus, + language::unary_not, + language::subscript_expression, + language::tuple_type_specifier, + language::type_expression, + language::unary_expression, + language::name_subscript_expression>, + parse_tree::remove_content::on<language::plus_op, + language::minus_op, + language::multiply_op, + language::divide_op, + language::lesser_op, + language::lesser_or_eq_op, + language::greater_op, + language::greater_or_eq_op, + language::eqeq_op, + language::not_eq_op, + language::and_op, + language::or_op, + language::xor_op, + language::eq_op, + language::multiplyeq_op, + language::divideeq_op, + language::pluseq_op, + language::minuseq_op, + language::unary_plusplus, + language::unary_minusminus, + language::post_minusminus, + language::post_plusplus>, + ASTBuilder::simplify_for_statement_block::on<language::for_statement_block>, + parse_tree::discard_empty::on<language::ignored, language::semicol, language::block>, + ASTBuilder::simplify_node_list:: + on<language::name_list, language::lvalue_list, language::function_argument_list, language::expression_list>, + ASTBuilder::simplify_statement_block::on<language::statement_block>, + ASTBuilder::simplify_for_init::on<language::for_init>, + ASTBuilder::simplify_for_test::on<language::for_test>, + ASTBuilder::simplify_for_post::on<language::for_post>, + ASTBuilder::simplify_stream_statement::on<language::ostream_statement>>; + +template <typename InputT> +std::unique_ptr<ASTNode> +ASTBuilder::build(InputT& input) +{ + std::unique_ptr root_node = parse_tree::parse<language::grammar, ASTNode, selector, nothing, language::errors>(input); + + // build initial symbol tables + std::shared_ptr symbol_table = std::make_shared<SymbolTable>(); + + root_node->m_symbol_table = symbol_table; + + return root_node; +} + +template std::unique_ptr<ASTNode> ASTBuilder::build(read_input<>& input); +template std::unique_ptr<ASTNode> ASTBuilder::build(string_input<>& input); diff --git a/src/language/ast/ASTBuilder.hpp b/src/language/ast/ASTBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8939a09385277dc05255a643bfb46c877a7901bb --- /dev/null +++ b/src/language/ast/ASTBuilder.hpp @@ -0,0 +1,26 @@ +#ifndef AST_BUILDER_HPP +#define AST_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +#include <memory> + +struct ASTBuilder +{ + private: + struct rearrange; + struct simplify_unary; + struct simplify_node_list; + struct simplify_statement_block; + struct simplify_for_statement_block; + struct simplify_for_init; + struct simplify_for_test; + struct simplify_for_post; + struct simplify_stream_statement; + + public: + template <typename InputT> + static std::unique_ptr<ASTNode> build(InputT& input); +}; + +#endif // AST_BUILDER_HPP diff --git a/src/language/ast/ASTModulesImporter.cpp b/src/language/ast/ASTModulesImporter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..197f9dcdd33a7e268a550cea12464567ff0f93b5 --- /dev/null +++ b/src/language/ast/ASTModulesImporter.cpp @@ -0,0 +1,42 @@ +#include <language/ast/ASTModulesImporter.hpp> + +#include <language/PEGGrammar.hpp> + +void +ASTModulesImporter::_importModule(ASTNode& import_node) +{ + Assert(import_node.is_type<language::import_instruction>()); + Assert(import_node.children[0]->is_type<language::module_name>()); + + const ASTNode& module_name_node = *import_node.children[0]; + const std::string module_name = module_name_node.string(); + + if (auto [i_module_name, success] = m_imported_modules.insert(module_name); not success) { + std::cout << " * ignoring '" << rang::fgB::green << module_name << rang::style::reset + << "' module, already imported\n"; + return; + } + + std::cout << " * importing '" << rang::fgB::green << module_name << rang::style::reset << "' module\n"; + + m_module_repository.populateSymbolTable(module_name_node, m_symbol_table); +} + +void +ASTModulesImporter::_importAllModules(ASTNode& node) +{ + if (node.is_type<language::import_instruction>()) { + this->_importModule(node); + } else { + for (auto& child : node.children) { + this->_importAllModules(*child); + } + } +} + +ASTModulesImporter::ASTModulesImporter(ASTNode& root_node) : m_symbol_table{*root_node.m_symbol_table} +{ + Assert(root_node.is_root()); + this->_importAllModules(root_node); + std::cout << " - loaded modules\n"; +} diff --git a/src/language/ast/ASTModulesImporter.hpp b/src/language/ast/ASTModulesImporter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2b8c081fdee5ef48dd9594a79ceeca13e52fdedc --- /dev/null +++ b/src/language/ast/ASTModulesImporter.hpp @@ -0,0 +1,30 @@ +#ifndef AST_MODULES_IMPORTER_HPP +#define AST_MODULES_IMPORTER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/modules/ModuleRepository.hpp> + +#include <set> +#include <string> + +class SymbolTable; + +class ASTModulesImporter +{ + std::set<std::string> m_imported_modules; + SymbolTable& m_symbol_table; + + ModuleRepository m_module_repository; + + void _importModule(ASTNode& import_node); + void _importAllModules(ASTNode& node); + + public: + ASTModulesImporter(ASTNode& root_node); + + ASTModulesImporter(const ASTModulesImporter&) = delete; + + ~ASTModulesImporter() = default; +}; + +#endif // AST_MODULES_IMPORTER_HPP diff --git a/src/language/ast/ASTNode.hpp b/src/language/ast/ASTNode.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b3dd41ca65faae6324d040aa7f4b66c078f45f6c --- /dev/null +++ b/src/language/ast/ASTNode.hpp @@ -0,0 +1,100 @@ +#ifndef AST_NODE_HPP +#define AST_NODE_HPP + +#include <language/ast/ASTNodeDataType.hpp> +#include <language/node_processor/ExecutionPolicy.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/DataVariant.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +#include <pegtl/contrib/parse_tree.hpp> + +using namespace TAO_PEGTL_NAMESPACE; + +class SymbolTable; + +class ASTNode : public parse_tree::basic_node<ASTNode> +{ + private: + PUGS_INLINE + decltype(m_end) + _getEnd() const + { + if (not this->has_content()) { + if (this->children.size() > 0) { + return this->children[children.size() - 1]->_getEnd(); + } + } + return m_end; + } + + PUGS_INLINE + decltype(m_begin) + _getBegin() const + { + if (not this->has_content()) { + if (this->children.size() > 0) { + return this->children[0]->_getBegin(); + } + } + return m_begin; + } + + public: + std::shared_ptr<SymbolTable> m_symbol_table; + std::unique_ptr<INodeProcessor> m_node_processor; + + ASTNodeDataType m_data_type{ASTNodeDataType::undefined_t}; + + [[nodiscard]] PUGS_INLINE std::string + string() const + { + if (this->has_content()) { + return this->parse_tree::basic_node<ASTNode>::string(); + } else { + auto end = this->_getEnd(); + auto begin = this->_getBegin(); + if (end.data != nullptr) { + return std::string{begin.data, end.data}; + } + return {"<optimized out>"}; + } + } + + [[nodiscard]] PUGS_INLINE std::string_view + string_view() const + { + if (this->has_content()) { + return this->parse_tree::basic_node<ASTNode>::string_view(); + } else { + auto end = this->_getEnd(); + auto begin = this->_getBegin(); + if (end.data != nullptr) { + return std::string_view(begin.data, end.data - begin.data); + } + return {"<optimized out>"}; + } + } + + PUGS_INLINE + std::string + name() const noexcept + { + return demangle(std::string{this->type}); + } + + PUGS_INLINE + DataVariant + execute(ExecutionPolicy& exec_policy) + { + Assert(m_node_processor, "undefined node processor"); + if (exec_policy.exec()) { + return m_node_processor->execute(exec_policy); + } else { + return {}; + } + } +}; + +#endif // AST_NODE_HPP diff --git a/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43bd40932c82310d039f851c9ddc810744c6f72b --- /dev/null +++ b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp @@ -0,0 +1,435 @@ +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> + +#include <algebra/TinyVector.hpp> +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNodeNaturalConversionChecker.hpp> +#include <language/node_processor/AffectationProcessor.hpp> + +#include <utils/Exceptions.hpp> + +ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode& n) +{ + auto set_affectation_processor = [](ASTNode& n, const auto& operator_v) { + auto set_affectation_processor_for_data = [&](const auto& value, const ASTNodeDataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + using ValueT = std::decay_t<decltype(value)>; + + switch (data_type) { + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined operand type for affectation", + std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto set_affectation_processor_for_vector_data = [&](const auto& value, const ASTNodeDataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + using ValueT = std::decay_t<decltype(value)>; + + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + switch (data_type) { + case ASTNodeDataType::vector_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, ValueT>>(n); + break; + } + case ASTNodeDataType::list_t: { + n.m_node_processor = std::make_unique<AffectationToTinyVectorFromListProcessor<OperatorT, ValueT>>(n); + break; + } + case ASTNodeDataType::bool_t: { + if constexpr (std::is_same_v<ValueT, TinyVector<1>>) { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n); + break; + } + } + case ASTNodeDataType::unsigned_int_t: { + if constexpr (std::is_same_v<ValueT, TinyVector<1>>) { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n); + break; + } + } + case ASTNodeDataType::int_t: { + if constexpr (std::is_same_v<ValueT, TinyVector<1>>) { + if (n.children[1]->is_type<language::integer>()) { + if (std::stoi(n.children[1]->string()) == 0) { + n.m_node_processor = std::make_unique<AffectationFromZeroProcessor<ValueT>>(n); + break; + } + } + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n); + break; + } else if (n.children[1]->is_type<language::integer>()) { + if (std::stoi(n.children[1]->string()) == 0) { + n.m_node_processor = std::make_unique<AffectationFromZeroProcessor<ValueT>>(n); + break; + } + } + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid integral value", std::vector{n.children[1]->begin()}); + // LCOV_EXCL_STOP + } + case ASTNodeDataType::double_t: { + if constexpr (std::is_same_v<ValueT, TinyVector<1>>) { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n); + break; + } + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid operand type", std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + } else if constexpr (std::is_same_v<OperatorT, language::pluseq_op> or + std::is_same_v<OperatorT, language::minuseq_op>) { + switch (data_type) { + case ASTNodeDataType::vector_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, ValueT>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid operand type", std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + } else if constexpr (std::is_same_v<OperatorT, language::multiplyeq_op>) { + switch (data_type) { + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n); + break; + } + default: { + throw parse_error("expecting scalar operand type", std::vector{n.children[1]->begin()}); + } + } + } else { + throw parse_error("invalid affectation operator for " + dataTypeName(n.m_data_type), std::vector{n.begin()}); + } + }; + + auto set_affectation_processor_for_string_data = [&](const ASTNodeDataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + + if constexpr (std::is_same_v<OperatorT, language::eq_op> or std::is_same_v<OperatorT, language::pluseq_op>) { + switch (data_type) { + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, double>>(n); + break; + } + case ASTNodeDataType::string_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, std::string>>(n); + break; + } + case ASTNodeDataType::vector_t: { + switch (data_type.dimension()) { + case 1: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, TinyVector<1>>>(n); + break; + } + case 2: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, TinyVector<2>>>(n); + break; + } + case 3: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, std::string, TinyVector<3>>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector dimension for string affectation", + std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined operand type for string affectation", + std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + } else { + throw parse_error("invalid affectation operator for string", std::vector{n.begin()}); + } + }; + + auto set_affectation_processor_for_embedded_data = [&](const ASTNodeDataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + switch (data_type) { + case ASTNodeDataType::type_id_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, EmbeddedData, EmbeddedData>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined operand type for embedded data affectation", + std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + } else { + throw parse_error("invalid affectation operator for '" + dataTypeName(n.children[0]->m_data_type) + "'", + std::vector{n.begin()}); + } + }; + + auto set_affectation_processor_for_tuple_data = [&](const ASTNodeDataType& content_data_type, + const ASTNodeDataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + if ((data_type == ASTNodeDataType::list_t) or (data_type == ASTNodeDataType::tuple_t)) { + switch (content_data_type) { + case ASTNodeDataType::type_id_t: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, EmbeddedData>>(n); + break; + } + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, double>>(n); + break; + } + case ASTNodeDataType::string_t: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, std::string>>(n); + break; + } + case ASTNodeDataType::vector_t: { + switch (content_data_type.dimension()) { + case 1: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, TinyVector<1>>>(n); + break; + } + case 2: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, TinyVector<2>>>(n); + break; + } + case 3: { + n.m_node_processor = std::make_unique<AffectationToTupleFromListProcessor<OperatorT, TinyVector<3>>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector dimension for tuple affectation", + std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid tuple content " + dataTypeName(content_data_type)); + } + // LCOV_EXCL_STOP + } + } else { + switch (content_data_type) { + case ASTNodeDataType::type_id_t: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, EmbeddedData>>(n); + break; + } + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, double>>(n); + break; + } + case ASTNodeDataType::string_t: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, std::string>>(n); + break; + } + case ASTNodeDataType::vector_t: { + switch (content_data_type.dimension()) { + case 1: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, TinyVector<1>>>(n); + break; + } + case 2: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, TinyVector<2>>>(n); + break; + } + case 3: { + n.m_node_processor = std::make_unique<AffectationToTupleProcessor<OperatorT, TinyVector<3>>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector dimension for tuple affectation", + std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined operand type for tuple affectation", + std::vector{n.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + } + } else { + throw parse_error("invalid affectation operator for '" + dataTypeName(n.children[0]->m_data_type) + "'", + std::vector{n.begin()}); + } + }; + + auto set_affectation_processor_for_value = [&](const ASTNodeDataType& value_type) { + const ASTNodeDataType data_type = n.children[1]->m_data_type; + + switch (value_type) { + case ASTNodeDataType::bool_t: { + set_affectation_processor_for_data(bool{}, data_type); + break; + } + case ASTNodeDataType::unsigned_int_t: { + set_affectation_processor_for_data(uint64_t{}, data_type); + break; + } + case ASTNodeDataType::int_t: { + set_affectation_processor_for_data(int64_t{}, data_type); + break; + } + case ASTNodeDataType::double_t: { + set_affectation_processor_for_data(double{}, data_type); + break; + } + case ASTNodeDataType::vector_t: { + switch (value_type.dimension()) { + case 1: { + set_affectation_processor_for_vector_data(TinyVector<1>{}, data_type); + break; + } + case 2: { + set_affectation_processor_for_vector_data(TinyVector<2>{}, data_type); + break; + } + case 3: { + set_affectation_processor_for_vector_data(TinyVector<3>{}, data_type); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: unexpected vector dimension", std::vector{n.begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + set_affectation_processor_for_string_data(data_type); + break; + } + case ASTNodeDataType::type_id_t: { + set_affectation_processor_for_embedded_data(data_type); + break; + } + case ASTNodeDataType::tuple_t: { + const ASTNodeDataType& content_type = value_type.contentType(); + set_affectation_processor_for_tuple_data(content_type, data_type); + break; + } + default: { + throw parse_error("unexpected error: undefined value type for affectation", + std::vector{n.children[0]->begin()}); + } + } + }; + + using OperatorT = std::decay_t<decltype(operator_v)>; + // Special treatment dedicated to R^1 to be able to initialize them + if (((n.m_data_type != n.children[1]->m_data_type) and (n.m_data_type == ASTNodeDataType::vector_t) and + (n.m_data_type.dimension() == 1)) or + // Special treatment for R^d vectors and operator *= + ((n.m_data_type == ASTNodeDataType::vector_t) and (n.children[1]->m_data_type != ASTNodeDataType::vector_t) and + std::is_same_v<OperatorT, language::multiplyeq_op>)) { + ASTNodeNaturalConversionChecker{*n.children[1], ASTNodeDataType::double_t}; + } else { + ASTNodeNaturalConversionChecker{*n.children[1], n.m_data_type}; + } + + set_affectation_processor_for_value(n.m_data_type); + }; + + if (n.is_type<language::eq_op>()) { + set_affectation_processor(n, language::eq_op{}); + } else if (n.is_type<language::multiplyeq_op>()) { + set_affectation_processor(n, language::multiplyeq_op{}); + } else if (n.is_type<language::divideeq_op>()) { + set_affectation_processor(n, language::divideeq_op{}); + } else if (n.is_type<language::pluseq_op>()) { + set_affectation_processor(n, language::pluseq_op{}); + } else if (n.is_type<language::minuseq_op>()) { + set_affectation_processor(n, language::minuseq_op{}); + } else { + throw parse_error("unexpected error: undefined affectation operator", std::vector{n.begin()}); + } +} diff --git a/src/language/ast/ASTNodeAffectationExpressionBuilder.hpp b/src/language/ast/ASTNodeAffectationExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..820fc90069e9f81e5c22dd41a7bf91925777799b --- /dev/null +++ b/src/language/ast/ASTNodeAffectationExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP +#define AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +struct ASTNodeAffectationExpressionBuilder +{ + ASTNodeAffectationExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.cpp b/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e50b84668b6cb11d900554002ade3d6ba2937608 --- /dev/null +++ b/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.cpp @@ -0,0 +1,32 @@ +#include <language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp> + +#include <algebra/TinyVector.hpp> +#include <language/node_processor/ArraySubscriptProcessor.hpp> + +ASTNodeArraySubscriptExpressionBuilder::ASTNodeArraySubscriptExpressionBuilder(ASTNode& node) +{ + auto& array_expression = *node.children[0]; + + if (array_expression.m_data_type == ASTNodeDataType::vector_t) { + switch (array_expression.m_data_type.dimension()) { + case 1: { + node.m_node_processor = std::make_unique<ArraySubscriptProcessor<TinyVector<1>>>(node); + break; + } + case 2: { + node.m_node_processor = std::make_unique<ArraySubscriptProcessor<TinyVector<2>>>(node); + break; + } + case 3: { + node.m_node_processor = std::make_unique<ArraySubscriptProcessor<TinyVector<3>>>(node); + break; + } + default: { + throw parse_error("unexpected error: invalid array dimension", array_expression.begin()); + break; + } + } + } else { + throw parse_error("unexpected error: invalid array type", array_expression.begin()); + } +} diff --git a/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp b/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5bf753a7707a5854d8e06c9c11e06f65aada3ad4 --- /dev/null +++ b/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp @@ -0,0 +1,12 @@ +#ifndef AST_NODE_ARRAY_SUBSCRIPT_EXPRESSION_BUILDER_HPP +#define AST_NODE_ARRAY_SUBSCRIPT_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTNodeArraySubscriptExpressionBuilder +{ + public: + ASTNodeArraySubscriptExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_ARRAY_SUBSCRIPT_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92074474abd0b1109feee7a53537deac2d4e44d4 --- /dev/null +++ b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp @@ -0,0 +1,206 @@ +#include <language/ast/ASTNodeBinaryOperatorExpressionBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/BinaryExpressionProcessor.hpp> +#include <language/node_processor/ConcatExpressionProcessor.hpp> + +ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(ASTNode& n) +{ + auto set_binary_operator_processor = [](ASTNode& n, const auto& operator_v) { + auto set_binary_operator_processor_for_data_b = [&](const auto data_a, const ASTNodeDataType& data_type_b) { + using OperatorT = std::decay_t<decltype(operator_v)>; + using DataTA = std::decay_t<decltype(data_a)>; + + if constexpr (std::is_same_v<DataTA, std::string>) { + if constexpr (std::is_same_v<OperatorT, language::plus_op>) { + switch (data_type_b) { + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<ConcatExpressionProcessor<bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<ConcatExpressionProcessor<uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<ConcatExpressionProcessor<int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<ConcatExpressionProcessor<double>>(n); + break; + } + case ASTNodeDataType::string_t: { + n.m_node_processor = std::make_unique<ConcatExpressionProcessor<std::string>>(n); + break; + } + default: { + throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()}); + } + } + + } else if constexpr ((std::is_same_v<OperatorT, language::eqeq_op>) or + (std::is_same_v<OperatorT, language::not_eq_op>)) { + if (data_type_b == ASTNodeDataType::string_t) { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, std::string>>(n); + } else { + throw parse_error("undefined operand type for binary operator", std::vector{n.begin()}); + } + } else { + throw parse_error("undefined operand type for binary operator", std::vector{n.begin()}); + } + } else if constexpr (std::is_same_v<DataTA, TinyVector<1>> or std::is_same_v<DataTA, TinyVector<2>> or + std::is_same_v<DataTA, TinyVector<3>>) { + if ((data_type_b == ASTNodeDataType::vector_t)) { + if constexpr (std::is_same_v<OperatorT, language::plus_op> or std::is_same_v<OperatorT, language::minus_op> or + std::is_same_v<OperatorT, language::eqeq_op> or + std::is_same_v<OperatorT, language::not_eq_op>) { + if (data_a.dimension() == data_type_b.dimension()) { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, DataTA>>(n); + } else { + throw parse_error("incompatible dimensions of operands", std::vector{n.begin()}); + } + } else { + throw parse_error("invalid binary operator", std::vector{n.begin()}); + } + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid operand type for binary operator", + std::vector{n.children[1]->begin()}); + // LCOV_EXCL_STOP + } + } else { + switch (data_type_b) { + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, double>>(n); + break; + } + case ASTNodeDataType::vector_t: { + if constexpr (std::is_same_v<OperatorT, language::multiply_op>) { + switch (data_type_b.dimension()) { + case 1: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, TinyVector<1>>>(n); + break; + } + case 2: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, TinyVector<2>>>(n); + break; + } + case 3: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, TinyVector<3>>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid dimension", std::vector{n.children[0]->begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + } + default: { + throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()}); + } + } + } + }; + + auto set_binary_operator_processor_for_data_a = [&](const ASTNodeDataType& data_type_a) { + const ASTNodeDataType data_type_b = n.children[1]->m_data_type; + switch (data_type_a) { + case ASTNodeDataType::bool_t: { + set_binary_operator_processor_for_data_b(bool{}, data_type_b); + break; + } + case ASTNodeDataType::unsigned_int_t: { + set_binary_operator_processor_for_data_b(uint64_t{}, data_type_b); + break; + } + case ASTNodeDataType::int_t: { + set_binary_operator_processor_for_data_b(int64_t{}, data_type_b); + break; + } + case ASTNodeDataType::double_t: { + set_binary_operator_processor_for_data_b(double{}, data_type_b); + break; + } + case ASTNodeDataType::string_t: { + set_binary_operator_processor_for_data_b(std::string{}, data_type_b); + break; + } + case ASTNodeDataType::vector_t: { + switch (data_type_a.dimension()) { + case 1: { + set_binary_operator_processor_for_data_b(TinyVector<1>{}, data_type_b); + break; + } + case 2: { + set_binary_operator_processor_for_data_b(TinyVector<2>{}, data_type_b); + break; + } + case 3: { + set_binary_operator_processor_for_data_b(TinyVector<3>{}, data_type_b); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid dimension", std::vector{n.children[0]->begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + default: { + throw parse_error("undefined operand type for binary operator", std::vector{n.children[0]->begin()}); + } + } + }; + + set_binary_operator_processor_for_data_a(n.children[0]->m_data_type); + }; + + if (n.is_type<language::multiply_op>()) { + set_binary_operator_processor(n, language::multiply_op{}); + } else if (n.is_type<language::divide_op>()) { + set_binary_operator_processor(n, language::divide_op{}); + } else if (n.is_type<language::plus_op>()) { + set_binary_operator_processor(n, language::plus_op{}); + } else if (n.is_type<language::minus_op>()) { + set_binary_operator_processor(n, language::minus_op{}); + + } else if (n.is_type<language::or_op>()) { + set_binary_operator_processor(n, language::or_op{}); + } else if (n.is_type<language::and_op>()) { + set_binary_operator_processor(n, language::and_op{}); + } else if (n.is_type<language::xor_op>()) { + set_binary_operator_processor(n, language::xor_op{}); + + } else if (n.is_type<language::greater_op>()) { + set_binary_operator_processor(n, language::greater_op{}); + } else if (n.is_type<language::greater_or_eq_op>()) { + set_binary_operator_processor(n, language::greater_or_eq_op{}); + } else if (n.is_type<language::lesser_op>()) { + set_binary_operator_processor(n, language::lesser_op{}); + } else if (n.is_type<language::lesser_or_eq_op>()) { + set_binary_operator_processor(n, language::lesser_or_eq_op{}); + } else if (n.is_type<language::eqeq_op>()) { + set_binary_operator_processor(n, language::eqeq_op{}); + } else if (n.is_type<language::not_eq_op>()) { + set_binary_operator_processor(n, language::not_eq_op{}); + } else { + throw parse_error("unexpected error: undefined binary operator", std::vector{n.begin()}); + } +} diff --git a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.hpp b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5ddad1d8c752cf8631970e8270e99d6ad82773ac --- /dev/null +++ b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP +#define AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +struct ASTNodeBinaryOperatorExpressionBuilder +{ + ASTNodeBinaryOperatorExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d914d7ee4799c9908253ffaa2958180a9d67bd3 --- /dev/null +++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp @@ -0,0 +1,390 @@ +#include <language/ast/ASTNodeBuiltinFunctionExpressionBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNodeDataTypeFlattener.hpp> +#include <language/ast/ASTNodeNaturalConversionChecker.hpp> +#include <language/node_processor/BuiltinFunctionProcessor.hpp> +#include <language/utils/SymbolTable.hpp> + +PUGS_INLINE std::unique_ptr<IFunctionArgumentConverter> +ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeDataType& parameter_type, + const ASTNodeSubDataType& argument_node_sub_data_type, + const size_t argument_number) +{ + auto get_function_argument_converter_for = + [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> { + using ParameterT = std::decay_t<decltype(parameter_v)>; + switch (argument_node_sub_data_type.m_data_type) { + case ASTNodeDataType::bool_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, bool>>(argument_number); + } + case ASTNodeDataType::unsigned_int_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, uint64_t>>(argument_number); + } + case ASTNodeDataType::int_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, int64_t>>(argument_number); + } + case ASTNodeDataType::double_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, double>>(argument_number); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid argument type for function", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_argument_converter_for_vector = + [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> { + using ParameterT = std::decay_t<decltype(parameter_v)>; + + if constexpr (std::is_same_v<ParameterT, TinyVector<1>>) { + switch (argument_node_sub_data_type.m_data_type) { + case ASTNodeDataType::vector_t: { + if (argument_node_sub_data_type.m_data_type.dimension() == 1) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(argument_number); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid argument dimension", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::bool_t: { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, bool>>(argument_number); + } + case ASTNodeDataType::int_t: { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, int64_t>>(argument_number); + } + case ASTNodeDataType::unsigned_int_t: { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, uint64_t>>(argument_number); + } + case ASTNodeDataType::double_t: { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, double>>(argument_number); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid argument type", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + } else { + switch (argument_node_sub_data_type.m_data_type) { + case ASTNodeDataType::vector_t: { + if (argument_node_sub_data_type.m_data_type.dimension() == parameter_v.dimension()) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(argument_number); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid argument dimension", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::list_t: { + if (argument_node_sub_data_type.m_parent_node.children.size() == parameter_v.dimension()) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(argument_number); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid argument dimension", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::int_t: { + if (argument_node_sub_data_type.m_parent_node.is_type<language::integer>()) { + if (std::stoi(argument_node_sub_data_type.m_parent_node.string()) == 0) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ZeroType>>(argument_number); + } + } + [[fallthrough]]; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid argument type", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + } + }; + + auto get_function_argument_to_string_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> { + return std::make_unique<FunctionArgumentToStringConverter>(argument_number); + }; + + auto get_function_argument_to_type_id_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> { + switch (argument_node_sub_data_type.m_data_type) { + case ASTNodeDataType::type_id_t: { + return std::make_unique<FunctionArgumentConverter<EmbeddedData, EmbeddedData>>(argument_number); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid argument type for function", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_argument_to_tuple_converter = + [&](const auto& parameter_content_v) -> std::unique_ptr<IFunctionArgumentConverter> { + using ParameterContentT = std::decay_t<decltype(parameter_content_v)>; + const auto& arg_data_type = argument_node_sub_data_type.m_data_type; + switch (arg_data_type) { + case ASTNodeDataType::tuple_t: { + const auto& tuple_content_type = arg_data_type.contentType(); + switch (tuple_content_type) { + case ASTNodeDataType::type_id_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, EmbeddedData>>(argument_number); + } + case ASTNodeDataType::bool_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, bool>>(argument_number); + } + case ASTNodeDataType::unsigned_int_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, uint64_t>>(argument_number); + } + case ASTNodeDataType::int_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, int64_t>>(argument_number); + } + case ASTNodeDataType::double_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, double>>(argument_number); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError(dataTypeName(tuple_content_type) + " unexpected tuple content type of argument "); + } + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::list_t: { + return std::make_unique<FunctionListArgumentConverter<ParameterContentT, ParameterContentT>>(argument_number); + } + case ASTNodeDataType::type_id_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, EmbeddedData>>(argument_number); + } + case ASTNodeDataType::bool_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, bool>>(argument_number); + } + case ASTNodeDataType::unsigned_int_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, uint64_t>>(argument_number); + } + case ASTNodeDataType::int_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, int64_t>>(argument_number); + } + case ASTNodeDataType::double_t: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, double>>(argument_number); + } + case ASTNodeDataType::vector_t: { + switch (arg_data_type.dimension()) { + case 1: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyVector<1>>>(argument_number); + } + case 2: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyVector<2>>>(argument_number); + } + case 3: { + return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyVector<3>>>(argument_number); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError(dataTypeName(arg_data_type) + " unexpected dimension of vector"); + } + // LCOV_EXCL_STOP + } + } + // LCOV_EXCL_START + default: { + throw UnexpectedError(dataTypeName(arg_data_type) + " argument to tuple "); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_argument_to_function_id_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> { + switch (argument_node_sub_data_type.m_data_type) { + case ASTNodeDataType::function_t: { + const ASTNode& parent_node = argument_node_sub_data_type.m_parent_node; + auto symbol_table = parent_node.m_symbol_table; + + return std::make_unique<FunctionArgumentToFunctionSymbolIdConverter>(argument_number, symbol_table); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid argument type for function", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_argument_converter_for_argument_type = [&]() { + switch (parameter_type) { + case ASTNodeDataType::bool_t: { + return get_function_argument_converter_for(bool{}); + } + case ASTNodeDataType::unsigned_int_t: { + return get_function_argument_converter_for(uint64_t{}); + } + case ASTNodeDataType::int_t: { + return get_function_argument_converter_for(int64_t{}); + } + case ASTNodeDataType::double_t: { + return get_function_argument_converter_for(double{}); + } + case ASTNodeDataType::vector_t: { + switch (parameter_type.dimension()) { + case 1: { + return get_function_argument_converter_for_vector(TinyVector<1>{}); + } + case 2: { + return get_function_argument_converter_for_vector(TinyVector<2>{}); + } + case 3: { + return get_function_argument_converter_for_vector(TinyVector<3>{}); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined parameter type for function", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::string_t: { + return get_function_argument_to_string_converter(); + } + case ASTNodeDataType::type_id_t: { + return get_function_argument_to_type_id_converter(); + } + case ASTNodeDataType::function_t: { + return get_function_argument_to_function_id_converter(); + } + case ASTNodeDataType::tuple_t: { + switch (parameter_type.contentType()) { + case ASTNodeDataType::type_id_t: { + return get_function_argument_to_tuple_converter(EmbeddedData{}); + } + case ASTNodeDataType::bool_t: { + return get_function_argument_to_tuple_converter(bool{}); + } + case ASTNodeDataType::unsigned_int_t: { + return get_function_argument_to_tuple_converter(uint64_t{}); + } + case ASTNodeDataType::int_t: { + return get_function_argument_to_tuple_converter(int64_t{}); + } + case ASTNodeDataType::double_t: { + return get_function_argument_to_tuple_converter(double{}); + } + case ASTNodeDataType::vector_t: { + switch (parameter_type.dimension()) { + case 1: { + return get_function_argument_to_tuple_converter(TinyVector<1>{}); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: unexpected tuple content for function: '" + + dataTypeName(parameter_type) + "'", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::string_t: { + return get_function_argument_to_string_converter(); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: unexpected tuple content type for function", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined parameter type for function", + std::vector{argument_node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + if (parameter_type == ASTNodeDataType::vector_t and parameter_type.dimension() == 1) { + if (not isNaturalConversion(argument_node_sub_data_type.m_data_type, parameter_type)) { + ASTNodeNaturalConversionChecker{argument_node_sub_data_type, ASTNodeDataType::double_t}; + } + } else { + ASTNodeNaturalConversionChecker{argument_node_sub_data_type, parameter_type}; + } + + return get_function_argument_converter_for_argument_type(); +} + +PUGS_INLINE +void +ASTNodeBuiltinFunctionExpressionBuilder::_storeArgumentProcessor( + const std::vector<ASTNodeDataType>& parameter_type_list, + const ASTNodeDataTypeFlattener::FlattenedDataTypeList& flattened_datatype_list, + const size_t argument_number, + BuiltinFunctionProcessor& processor) +{ + processor.addArgumentConverter(this->_getArgumentConverter(parameter_type_list[argument_number], + flattened_datatype_list[argument_number], + argument_number)); +} + +PUGS_INLINE +void +ASTNodeBuiltinFunctionExpressionBuilder::_buildArgumentProcessors( + const std::vector<ASTNodeDataType>& parameter_type_list, + ASTNode& node, + BuiltinFunctionProcessor& processor) +{ + ASTNode& argument_nodes = *node.children[1]; + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list; + ASTNodeDataTypeFlattener{argument_nodes, flattened_datatype_list}; + + const size_t arguments_number = flattened_datatype_list.size(); + const size_t parameters_number = parameter_type_list.size(); + + if (arguments_number != parameters_number) { + std::ostringstream error_message; + error_message << "bad number of arguments: expecting " << rang::fgB::yellow << parameters_number + << rang::style::reset << ", provided " << rang::fgB::yellow << arguments_number << rang::style::reset; + throw parse_error(error_message.str(), argument_nodes.begin()); + } + + for (size_t i = 0; i < arguments_number; ++i) { + this->_storeArgumentProcessor(parameter_type_list, flattened_datatype_list, i, processor); + } +} + +ASTNodeBuiltinFunctionExpressionBuilder::ASTNodeBuiltinFunctionExpressionBuilder(ASTNode& node) +{ + auto [i_function_symbol, found] = node.m_symbol_table->find(node.children[0]->string(), node.begin()); + Assert(found); + Assert(i_function_symbol->attributes().dataType() == ASTNodeDataType::builtin_function_t); + + uint64_t builtin_function_id = std::get<uint64_t>(i_function_symbol->attributes().value()); + + auto& builtin_function_embedder_table = node.m_symbol_table->builtinFunctionEmbedderTable(); + std::shared_ptr builtin_function_embedder = builtin_function_embedder_table[builtin_function_id]; + + std::vector<ASTNodeDataType> builtin_function_parameter_type_list = + builtin_function_embedder->getParameterDataTypes(); + + ASTNode& argument_nodes = *node.children[1]; + std::unique_ptr builtin_function_processor = std::make_unique<BuiltinFunctionProcessor>(argument_nodes); + + this->_buildArgumentProcessors(builtin_function_parameter_type_list, node, *builtin_function_processor); + + builtin_function_processor->setFunctionExpressionProcessor( + std::make_unique<BuiltinFunctionExpressionProcessor>(builtin_function_embedder)); + + node.m_node_processor = std::move(builtin_function_processor); +} diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.hpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7aded1c66c386f2b8d109594b1b5fcb7e313427c --- /dev/null +++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.hpp @@ -0,0 +1,34 @@ +#ifndef AST_NODE_C_FUNCTION_EXPRESSION_BUILDER_HPP +#define AST_NODE_C_FUNCTION_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeDataTypeFlattener.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class BuiltinFunctionProcessor; +class IFunctionArgumentConverter; + +class ASTNodeBuiltinFunctionExpressionBuilder +{ + private: + PUGS_INLINE std::unique_ptr<IFunctionArgumentConverter> _getArgumentConverter( + const ASTNodeDataType& parameter_type, + const ASTNodeSubDataType& argument_node_sub_data_type, + const size_t argument_number); + + PUGS_INLINE + void _storeArgumentProcessor(const std::vector<ASTNodeDataType>& parameter_type_list, + const ASTNodeDataTypeFlattener::FlattenedDataTypeList& flattened_datatype_list, + const size_t argument_number, + BuiltinFunctionProcessor& _processor); + + PUGS_INLINE + void _buildArgumentProcessors(const std::vector<ASTNodeDataType>& parameter_type_list, + ASTNode& node, + BuiltinFunctionProcessor& _processor); + + public: + ASTNodeBuiltinFunctionExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_C_FUNCTION_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeDataType.cpp b/src/language/ast/ASTNodeDataType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18b812c0e7bb7c62466a7bce6b1dfd279eacec43 --- /dev/null +++ b/src/language/ast/ASTNodeDataType.cpp @@ -0,0 +1,120 @@ +#include <language/ast/ASTNodeDataType.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <utils/PugsAssert.hpp> + +ASTNodeDataType +getVectorDataType(const ASTNode& type_node) +{ + if (not(type_node.is_type<language::vector_type>() and (type_node.children.size() == 2))) { + throw parse_error("unexpected node type", type_node.begin()); + } + ASTNode& dimension_node = *type_node.children[1]; + if (not dimension_node.is_type<language::integer>()) { + throw parse_error("unexpected non integer constant dimension", dimension_node.begin()); + } + const size_t dimension = std::stol(dimension_node.string()); + return ASTNodeDataType{ASTNodeDataType::vector_t, dimension}; +} + +std::string +dataTypeName(const ASTNodeDataType& data_type) +{ + std::string name; + switch (data_type) { + case ASTNodeDataType::undefined_t: + name = "undefined"; + break; + case ASTNodeDataType::bool_t: + name = "B"; + break; + case ASTNodeDataType::unsigned_int_t: + name = "N"; + break; + case ASTNodeDataType::int_t: + name = "Z"; + break; + case ASTNodeDataType::double_t: + name = "R"; + break; + case ASTNodeDataType::vector_t: + name = "R^" + std::to_string(data_type.dimension()); + break; + case ASTNodeDataType::tuple_t: + name = "tuple(" + dataTypeName(data_type.contentType()) + ')'; + break; + case ASTNodeDataType::list_t: + name = "list"; + break; + case ASTNodeDataType::string_t: + name = "string"; + break; + case ASTNodeDataType::typename_t: + name = "typename"; + break; + case ASTNodeDataType::type_name_id_t: + name = "type_name_id"; + break; + case ASTNodeDataType::type_id_t: + name = data_type.nameOfTypeId(); + break; + case ASTNodeDataType::function_t: + name = "function"; + break; + case ASTNodeDataType::builtin_function_t: + name = "builtin_function"; + break; + case ASTNodeDataType::void_t: + name = "void"; + break; + } + return name; +} + +ASTNodeDataType +dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& data_type_2) +{ + if (data_type_1 == data_type_2) { + return data_type_1; + } else if ((std::max(data_type_1, data_type_2) <= ASTNodeDataType::double_t) and + (std::min(data_type_1, data_type_2) >= ASTNodeDataType::bool_t)) { + return std::max(data_type_1, data_type_2); + } else if ((data_type_1 == ASTNodeDataType::string_t) and (data_type_2 < ASTNodeDataType::string_t) and + (data_type_2 >= ASTNodeDataType::bool_t)) { + return data_type_1; + } else if ((data_type_1 >= ASTNodeDataType::bool_t) and (data_type_1 <= ASTNodeDataType::double_t) and + (data_type_2 == ASTNodeDataType::vector_t)) { + return data_type_2; + } else { + return ASTNodeDataType::undefined_t; + } +} + +bool +isNaturalConversion(const ASTNodeDataType& data_type, const ASTNodeDataType& target_data_type) +{ + if (target_data_type == data_type) { + if (data_type == ASTNodeDataType::type_id_t) { + return (data_type.nameOfTypeId() == target_data_type.nameOfTypeId()); + } else if (data_type == ASTNodeDataType::vector_t) { + return (data_type.dimension() == target_data_type.dimension()); + } else { + return true; + } + } else if (target_data_type == ASTNodeDataType::bool_t) { + return false; + } else if (target_data_type == ASTNodeDataType::unsigned_int_t) { + return ((data_type == ASTNodeDataType::int_t) or (data_type == ASTNodeDataType::bool_t)); + } else if (target_data_type == ASTNodeDataType::int_t) { + return ((data_type == ASTNodeDataType::unsigned_int_t) or (data_type == ASTNodeDataType::bool_t)); + } else if (target_data_type == ASTNodeDataType::double_t) { + return ((data_type == ASTNodeDataType::unsigned_int_t) or (data_type == ASTNodeDataType::int_t) or + (data_type == ASTNodeDataType::bool_t)); + } else if (target_data_type == ASTNodeDataType::string_t) { + return ((data_type >= ASTNodeDataType::bool_t) and (data_type < ASTNodeDataType::string_t)); + } else if (target_data_type == ASTNodeDataType::tuple_t) { + return isNaturalConversion(data_type, target_data_type.contentType()); + } + return false; +} diff --git a/src/language/ast/ASTNodeDataType.hpp b/src/language/ast/ASTNodeDataType.hpp new file mode 100644 index 0000000000000000000000000000000000000000..863a87dad0a3df9d3659b9c661336fbf5e384aca --- /dev/null +++ b/src/language/ast/ASTNodeDataType.hpp @@ -0,0 +1,106 @@ +#ifndef AST_NODE_DATA_TYPE_HPP +#define AST_NODE_DATA_TYPE_HPP + +#include <utils/PugsAssert.hpp> + +#include <limits> +#include <memory> +#include <string> + +class ASTNode; + +class ASTNodeDataType +{ + public: + enum DataType : int32_t + { + undefined_t = -1, + bool_t = 0, + int_t = 1, + unsigned_int_t = 2, + double_t = 3, + vector_t = 4, + tuple_t = 5, + list_t = 6, + string_t = 7, + typename_t = 10, + type_name_id_t = 11, + type_id_t = 21, + function_t = 22, + builtin_function_t = 23, + void_t = std::numeric_limits<int32_t>::max() + }; + + private: + DataType m_data_type; + std::shared_ptr<ASTNodeDataType> m_content_type; + size_t m_dimension; + std::string m_name_of_type_id; + + public: + PUGS_INLINE + size_t + dimension() const + { + return m_dimension; + } + + PUGS_INLINE + const ASTNodeDataType& + contentType() const + { + Assert(m_content_type); + return *m_content_type; + } + + PUGS_INLINE + const std::string& + nameOfTypeId() const + { + return m_name_of_type_id; + } + + PUGS_INLINE + operator const DataType&() const + { + return m_data_type; + } + + ASTNodeDataType& operator=(const ASTNodeDataType&) = default; + ASTNodeDataType& operator=(ASTNodeDataType&&) = default; + + ASTNodeDataType(DataType data_type) + : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{1}, m_name_of_type_id{"unknown"} + {} + + ASTNodeDataType(DataType data_type, const ASTNodeDataType& content_type) + : m_data_type{data_type}, + m_content_type{std::make_shared<ASTNodeDataType>(content_type)}, + m_dimension{1}, + m_name_of_type_id{"unknown"} + {} + + ASTNodeDataType(DataType data_type, size_t dimension) + : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{dimension}, m_name_of_type_id{"unknown"} + {} + + ASTNodeDataType(DataType data_type, const std::string& type_name) + : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{1}, m_name_of_type_id{type_name} + {} + + ASTNodeDataType(const ASTNodeDataType&) = default; + + ASTNodeDataType(ASTNodeDataType&&) = default; + + ~ASTNodeDataType() = default; +}; + +ASTNodeDataType getVectorDataType(const ASTNode& type_node); + +std::string dataTypeName(const ASTNodeDataType& data_type); + +ASTNodeDataType dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& data_type_2); + +bool isNaturalConversion(const ASTNodeDataType& data_type, const ASTNodeDataType& target_data_type); + +#endif // AST_NODE_DATA_TYPE_HPP diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96ff62bfc20cd9a6526f140d14a4cee7218e241d --- /dev/null +++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp @@ -0,0 +1,500 @@ +#include <language/ast/ASTNodeDataTypeBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNodeNaturalConversionChecker.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/PugsAssert.hpp> + +ASTNodeDataType +ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNode& name_node) const +{ + ASTNodeDataType data_type{ASTNodeDataType::undefined_t}; + if (type_node.is_type<language::type_expression>()) { + if (type_node.children.size() != name_node.children.size()) { + std::ostringstream message; + message << "number of product spaces (" << type_node.children.size() << ") " << rang::fgB::yellow + << type_node.string() << rang::style::reset << rang::style::bold << " differs from number of variables (" + << name_node.children.size() << ") " << rang::fgB::yellow << name_node.string() << rang::style::reset + << std::ends; + throw parse_error(message.str(), name_node.begin()); + } + + for (size_t i = 0; i < type_node.children.size(); ++i) { + auto& sub_type_node = *type_node.children[i]; + auto& sub_name_node = *name_node.children[i]; + _buildDeclarationNodeDataTypes(sub_type_node, sub_name_node); + } + data_type = ASTNodeDataType::typename_t; + } else { + if (type_node.is_type<language::B_set>()) { + data_type = ASTNodeDataType::bool_t; + } else if (type_node.is_type<language::Z_set>()) { + data_type = ASTNodeDataType::int_t; + } else if (type_node.is_type<language::N_set>()) { + data_type = ASTNodeDataType::unsigned_int_t; + } else if (type_node.is_type<language::R_set>()) { + data_type = ASTNodeDataType::double_t; + } else if (type_node.is_type<language::vector_type>()) { + data_type = getVectorDataType(type_node); + } else if (type_node.is_type<language::tuple_type_specifier>()) { + const auto& content_node = type_node.children[0]; + + if (content_node->is_type<language::type_name_id>()) { + const std::string& type_name_id = content_node->string(); + + auto& symbol_table = *type_node.m_symbol_table; + + const auto [i_type_symbol, found] = symbol_table.find(type_name_id, content_node->begin()); + if (not found) { + throw parse_error("undefined type identifier", std::vector{content_node->begin()}); + } else if (i_type_symbol->attributes().dataType() != ASTNodeDataType::type_name_id_t) { + std::ostringstream os; + os << "invalid type identifier, '" << type_name_id << "' was previously defined as a '" + << dataTypeName(i_type_symbol->attributes().dataType()) << "'" << std::ends; + throw parse_error(os.str(), std::vector{content_node->begin()}); + } + + content_node->m_data_type = ASTNodeDataType{ASTNodeDataType::type_id_t, type_name_id}; + } else if (content_node->is_type<language::B_set>()) { + content_node->m_data_type = ASTNodeDataType::bool_t; + } else if (content_node->is_type<language::Z_set>()) { + content_node->m_data_type = ASTNodeDataType::int_t; + } else if (content_node->is_type<language::N_set>()) { + content_node->m_data_type = ASTNodeDataType::unsigned_int_t; + } else if (content_node->is_type<language::R_set>()) { + content_node->m_data_type = ASTNodeDataType::double_t; + } else if (content_node->is_type<language::vector_type>()) { + content_node->m_data_type = getVectorDataType(*type_node.children[0]); + } else if (content_node->is_type<language::string_type>()) { + content_node->m_data_type = ASTNodeDataType::string_t; + } else { + // LCOV_EXCL_START + throw UnexpectedError("unexpected content type in tuple"); + // LCOV_EXCL_STOP + } + + data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, content_node->m_data_type}; + } else if (type_node.is_type<language::string_type>()) { + data_type = ASTNodeDataType::string_t; + } else if (type_node.is_type<language::type_name_id>()) { + const std::string& type_name_id = type_node.string(); + + auto& symbol_table = *type_node.m_symbol_table; + + auto [i_type_symbol, found] = symbol_table.find(type_name_id, type_node.begin()); + if (not found) { + throw parse_error("undefined type identifier", std::vector{type_node.begin()}); + } else if (i_type_symbol->attributes().dataType() != ASTNodeDataType::type_name_id_t) { + std::ostringstream os; + os << "invalid type identifier, '" << type_name_id << "' was previously defined as a '" + << dataTypeName(i_type_symbol->attributes().dataType()) << "'" << std::ends; + throw parse_error(os.str(), std::vector{type_node.begin()}); + } + + data_type = ASTNodeDataType{ASTNodeDataType::type_id_t, type_name_id}; + } + + if (name_node.is_type<language::name_list>()) { + throw parse_error("unexpected variable list for single space", std::vector{name_node.begin()}); + } + + Assert(name_node.is_type<language::name>()); + name_node.m_data_type = data_type; + + const std::string& symbol = name_node.string(); + + std::shared_ptr<SymbolTable>& symbol_table = name_node.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(symbol, name_node.begin()); + Assert(found); + i_symbol->attributes().setDataType(name_node.m_data_type); + } + + Assert(data_type != ASTNodeDataType::undefined_t); + return data_type; +} + +void +ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const +{ + if (n.is_type<language::block>() or n.is_type<language::for_statement>()) { + for (auto& child : n.children) { + this->_buildNodeDataTypes(*child); + } + + if (n.is_type<language::for_statement>()) { + const ASTNode& test_node = *n.children[1]; + + if (not n.children[1]->is_type<language::for_test>()) { + ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t}; + } // in the case of empty for_test (not simplified node), nothing to check! + } + + n.m_data_type = ASTNodeDataType::void_t; + } else { + if (n.has_content()) { + if (n.is_type<language::import_instruction>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is_type<language::module_name>()) { + n.m_data_type = ASTNodeDataType::string_t; + + } else if (n.is_type<language::true_kw>() or n.is_type<language::false_kw>()) { + n.m_data_type = ASTNodeDataType::bool_t; + } else if (n.is_type<language::real>()) { + n.m_data_type = ASTNodeDataType::double_t; + } else if (n.is_type<language::integer>()) { + n.m_data_type = ASTNodeDataType::int_t; + } else if (n.is_type<language::vector_type>()) { + n.m_data_type = getVectorDataType(n); + + } else if (n.is_type<language::tuple_expression>()) { + n.m_data_type = ASTNodeDataType::list_t; + + } else if (n.is_type<language::literal>()) { + n.m_data_type = ASTNodeDataType::string_t; + } else if (n.is_type<language::cout_kw>() or n.is_type<language::cerr_kw>() or n.is_type<language::clog_kw>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is_type<language::var_declaration>()) { + auto& name_node = *(n.children[0]); + auto& type_node = *(n.children[1]); + + type_node.m_data_type = _buildDeclarationNodeDataTypes(type_node, name_node); + n.m_data_type = type_node.m_data_type; + } else if (n.is_type<language::fct_declaration>()) { + n.children[0]->m_data_type = ASTNodeDataType::function_t; + + const std::string& symbol = n.children[0]->string(); + auto [i_symbol, success] = n.m_symbol_table->find(symbol, n.children[0]->begin()); + + auto& function_table = n.m_symbol_table->functionTable(); + + uint64_t function_id = std::get<uint64_t>(i_symbol->attributes().value()); + FunctionDescriptor& function_descriptor = function_table[function_id]; + + ASTNode& parameters_domain_node = *function_descriptor.domainMappingNode().children[0]; + ASTNode& parameters_name_node = *function_descriptor.definitionNode().children[0]; + + { // Function data type + const std::string& symbol = n.children[0]->string(); + + std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(symbol, n.children[0]->begin()); + Assert(found); + i_symbol->attributes().setDataType(n.children[0]->m_data_type); + } + + const size_t nb_parameter_domains = + (parameters_domain_node.is_type<language::type_expression>()) ? parameters_domain_node.children.size() : 1; + const size_t nb_parameter_names = + (parameters_name_node.children.size() > 0) ? parameters_name_node.children.size() : 1; + + if (nb_parameter_domains != nb_parameter_names) { + std::ostringstream message; + message << "note: number of product spaces (" << nb_parameter_domains << ") " << rang::fgB::yellow + << parameters_domain_node.string() << rang::style::reset << rang::style::bold + << " differs from number of variables (" << nb_parameter_names << ") " << rang::fgB::yellow + << parameters_name_node.string() << rang::style::reset << std::ends; + throw parse_error(message.str(), parameters_domain_node.begin()); + } + + auto simple_type_allocator = [&](const ASTNode& type_node, ASTNode& symbol_node) { + Assert(symbol_node.is_type<language::name>()); + ASTNodeDataType data_type{ASTNodeDataType::undefined_t}; + if (type_node.is_type<language::B_set>()) { + data_type = ASTNodeDataType::bool_t; + } else if (type_node.is_type<language::Z_set>()) { + data_type = ASTNodeDataType::int_t; + } else if (type_node.is_type<language::N_set>()) { + data_type = ASTNodeDataType::unsigned_int_t; + } else if (type_node.is_type<language::R_set>()) { + data_type = ASTNodeDataType::double_t; + } else if (type_node.is_type<language::vector_type>()) { + data_type = getVectorDataType(type_node); + } else if (type_node.is_type<language::string_type>()) { + data_type = ASTNodeDataType::string_t; + } + + // LCOV_EXCL_START + if (data_type == ASTNodeDataType::undefined_t) { + throw parse_error("invalid parameter type", type_node.begin()); + } + // LCOV_EXCL_STOP + + symbol_node.m_data_type = data_type; + const std::string& symbol = symbol_node.string(); + + std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(symbol, symbol_node.begin()); + Assert(found); + i_symbol->attributes().setDataType(data_type); + }; + + if (nb_parameter_domains == 1) { + simple_type_allocator(parameters_domain_node, parameters_name_node); + } else { + for (size_t i = 0; i < nb_parameter_domains; ++i) { + simple_type_allocator(*parameters_domain_node.children[i], *parameters_name_node.children[i]); + } + parameters_name_node.m_data_type = ASTNodeDataType::list_t; + } + + // build types for compound types + for (auto& child : parameters_domain_node.children) { + this->_buildNodeDataTypes(*child); + } + for (auto& child : parameters_name_node.children) { + this->_buildNodeDataTypes(*child); + } + + ASTNode& image_domain_node = *function_descriptor.domainMappingNode().children[1]; + ASTNode& image_expression_node = *function_descriptor.definitionNode().children[1]; + + this->_buildNodeDataTypes(image_domain_node); + for (auto& child : image_domain_node.children) { + this->_buildNodeDataTypes(*child); + } + + const size_t nb_image_domains = + (image_domain_node.is_type<language::type_expression>()) ? image_domain_node.children.size() : 1; + const size_t nb_image_expressions = + (image_expression_node.is_type<language::expression_list>()) ? image_expression_node.children.size() : 1; + + if (nb_image_domains != nb_image_expressions) { + if (image_domain_node.is_type<language::vector_type>()) { + ASTNodeDataType image_type = getVectorDataType(image_domain_node); + if (image_type.dimension() != nb_image_expressions) { + std::ostringstream message; + message << "expecting " << image_type.dimension() << " scalar expressions or an " + << dataTypeName(image_type) << ", found " << nb_image_expressions << " scalar expressions" + << std::ends; + throw parse_error(message.str(), image_domain_node.begin()); + } + } else { + std::ostringstream message; + message << "number of image spaces (" << nb_image_domains << ") " << rang::fgB::yellow + << image_domain_node.string() << rang::style::reset << rang::style::bold + << " differs from number of expressions (" << nb_image_expressions << ") " << rang::fgB::yellow + << image_expression_node.string() << rang::style::reset << std::ends; + throw parse_error(message.str(), image_domain_node.begin()); + } + } + + auto check_image_type = [&](const ASTNode& image_node) { + ASTNodeDataType value_type{ASTNodeDataType::undefined_t}; + if (image_node.is_type<language::B_set>()) { + value_type = ASTNodeDataType::bool_t; + } else if (image_node.is_type<language::Z_set>()) { + value_type = ASTNodeDataType::int_t; + } else if (image_node.is_type<language::N_set>()) { + value_type = ASTNodeDataType::unsigned_int_t; + } else if (image_node.is_type<language::R_set>()) { + value_type = ASTNodeDataType::double_t; + } else if (image_node.is_type<language::vector_type>()) { + value_type = getVectorDataType(image_node); + } else if (image_node.is_type<language::string_type>()) { + value_type = ASTNodeDataType::string_t; + } + + // LCOV_EXCL_START + if (value_type == ASTNodeDataType::undefined_t) { + throw parse_error("invalid value type", image_node.begin()); + } + // LCOV_EXCL_STOP + }; + + if (image_domain_node.is_type<language::type_expression>()) { + for (size_t i = 0; i < image_domain_node.children.size(); ++i) { + check_image_type(*image_domain_node.children[i]); + } + image_domain_node.m_data_type = ASTNodeDataType::typename_t; + } else { + check_image_type(image_domain_node); + } + + n.m_data_type = ASTNodeDataType::void_t; + return; + } else if (n.is_type<language::name>()) { + std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(n.string(), n.begin()); + Assert(found); + n.m_data_type = i_symbol->attributes().dataType(); + } + } + for (auto& child : n.children) { + this->_buildNodeDataTypes(*child); + } + + if (n.is_type<language::break_kw>() or n.is_type<language::continue_kw>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is_type<language::eq_op>() or n.is_type<language::multiplyeq_op>() or + n.is_type<language::divideeq_op>() or n.is_type<language::pluseq_op>() or + n.is_type<language::minuseq_op>()) { + n.m_data_type = n.children[0]->m_data_type; + } else if (n.is_type<language::type_mapping>() or n.is_type<language::function_definition>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is_type<language::for_post>() or n.is_type<language::for_init>() or + n.is_type<language::for_statement_block>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is_type<language::for_test>()) { + n.m_data_type = ASTNodeDataType::bool_t; + } else if (n.is_type<language::statement_block>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is_type<language::if_statement>() or n.is_type<language::while_statement>()) { + n.m_data_type = ASTNodeDataType::void_t; + + const ASTNode& test_node = *n.children[0]; + ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t}; + + } else if (n.is_type<language::do_while_statement>()) { + n.m_data_type = ASTNodeDataType::void_t; + + const ASTNode& test_node = *n.children[1]; + ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t}; + + } else if (n.is_type<language::unary_not>()) { + n.m_data_type = ASTNodeDataType::bool_t; + + const ASTNode& operand_node = *n.children[0]; + ASTNodeNaturalConversionChecker{operand_node, ASTNodeDataType::bool_t}; + + } else if (n.is_type<language::lesser_op>() or n.is_type<language::lesser_or_eq_op>() or + n.is_type<language::greater_op>() or n.is_type<language::greater_or_eq_op>() or + n.is_type<language::eqeq_op>() or n.is_type<language::not_eq_op>()) { + n.m_data_type = ASTNodeDataType::bool_t; + } else if (n.is_type<language::and_op>() or n.is_type<language::or_op>() or n.is_type<language::xor_op>()) { + n.m_data_type = ASTNodeDataType::bool_t; + + const ASTNode& lhs_node = *n.children[0]; + ASTNodeNaturalConversionChecker{lhs_node, ASTNodeDataType::bool_t}; + + const ASTNode& rhs_node = *n.children[1]; + ASTNodeNaturalConversionChecker{rhs_node, ASTNodeDataType::bool_t}; + + } else if (n.is_type<language::unary_minus>()) { + n.m_data_type = n.children[0]->m_data_type; + if ((n.children[0]->m_data_type == ASTNodeDataType::unsigned_int_t) or + (n.children[0]->m_data_type == ASTNodeDataType::bool_t)) { + n.m_data_type = ASTNodeDataType::int_t; + } else { + n.m_data_type = n.children[0]->m_data_type; + } + } else if (n.is_type<language::unary_plusplus>() or n.is_type<language::unary_minusminus>() or + n.is_type<language::post_plusplus>() or n.is_type<language::post_minusminus>()) { + n.m_data_type = n.children[0]->m_data_type; + } else if (n.is_type<language::plus_op>() or n.is_type<language::minus_op>() or + n.is_type<language::multiply_op>() or n.is_type<language::divide_op>()) { + const ASTNodeDataType type_0 = n.children[0]->m_data_type; + const ASTNodeDataType type_1 = n.children[1]->m_data_type; + if ((type_0 == ASTNodeDataType::bool_t) and (type_1 == ASTNodeDataType::bool_t)) { + n.m_data_type = ASTNodeDataType::int_t; + } else { + n.m_data_type = dataTypePromotion(type_0, type_1); + } + if (n.m_data_type == ASTNodeDataType::undefined_t) { + std::ostringstream message; + message << "undefined binary operator\n" + << "note: incompatible operand types " << n.children[0]->string() << " (" << dataTypeName(type_0) + << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')' << std::ends; + throw parse_error(message.str(), n.begin()); + } + } else if (n.is_type<language::function_evaluation>()) { + if (n.children[0]->m_data_type == ASTNodeDataType::function_t) { + const std::string& function_name = n.children[0]->string(); + auto [i_function_symbol, success] = n.m_symbol_table->find(function_name, n.children[0]->begin()); + + auto& function_table = n.m_symbol_table->functionTable(); + + uint64_t function_id = std::get<uint64_t>(i_function_symbol->attributes().value()); + FunctionDescriptor& function_descriptor = function_table[function_id]; + + ASTNode& image_domain_node = *function_descriptor.domainMappingNode().children[1]; + + ASTNodeDataType data_type{ASTNodeDataType::undefined_t}; + if (image_domain_node.is_type<language::type_expression>()) { + data_type = image_domain_node.m_data_type; + } else { + if (image_domain_node.is_type<language::B_set>()) { + data_type = ASTNodeDataType::bool_t; + } else if (image_domain_node.is_type<language::Z_set>()) { + data_type = ASTNodeDataType::int_t; + } else if (image_domain_node.is_type<language::N_set>()) { + data_type = ASTNodeDataType::unsigned_int_t; + } else if (image_domain_node.is_type<language::R_set>()) { + data_type = ASTNodeDataType::double_t; + } else if (image_domain_node.is_type<language::vector_type>()) { + data_type = getVectorDataType(image_domain_node); + } else if (image_domain_node.is_type<language::string_type>()) { + data_type = ASTNodeDataType::string_t; + } + } + + Assert(data_type != ASTNodeDataType::undefined_t); // LCOV_EXCL_LINE + + n.m_data_type = data_type; + } else if (n.children[0]->m_data_type == ASTNodeDataType::builtin_function_t) { + const std::string builtin_function_name = n.children[0]->string(); + auto& symbol_table = *n.m_symbol_table; + + auto [i_symbol, success] = symbol_table.find(builtin_function_name, n.begin()); + Assert(success); + + uint64_t builtin_function_id = std::get<uint64_t>(i_symbol->attributes().value()); + auto builtin_function_embedder = symbol_table.builtinFunctionEmbedderTable()[builtin_function_id]; + Assert(builtin_function_embedder); + + n.m_data_type = builtin_function_embedder->getReturnDataType(); + } else { + std::ostringstream message; + message << "invalid function call\n" + << "note: '" << n.children[0]->string() << "' (type: " << dataTypeName(n.children[0]->m_data_type) + << ") is not a function!" << std::ends; + throw parse_error(message.str(), n.begin()); + } + } else if (n.is_type<language::subscript_expression>()) { + Assert(n.children.size() == 2, "invalid number of sub-expressions in array subscript expression"); + auto& array_expression = *n.children[0]; + auto& index_expression = *n.children[1]; + + ASTNodeNaturalConversionChecker{index_expression, ASTNodeDataType::int_t}; + if (array_expression.m_data_type != ASTNodeDataType::vector_t) { + std::ostringstream message; + message << "invalid types '" << rang::fgB::yellow << dataTypeName(array_expression.m_data_type) + << rang::style::reset << '[' << dataTypeName(index_expression.m_data_type) << ']' + << "' for array subscript" << std::ends; + + throw parse_error(message.str(), n.begin()); + } else { + n.m_data_type = ASTNodeDataType::double_t; + } + } else if (n.is_type<language::B_set>() or n.is_type<language::Z_set>() or n.is_type<language::N_set>() or + n.is_type<language::R_set>() or n.is_type<language::string_type>() or + n.is_type<language::vector_type>() or n.is_type<language::type_name_id>()) { + n.m_data_type = ASTNodeDataType::typename_t; + } else if (n.is_type<language::name_list>() or n.is_type<language::lvalue_list>() or + n.is_type<language::function_argument_list>() or n.is_type<language::expression_list>()) { + n.m_data_type = ASTNodeDataType::list_t; + } + } +} + +ASTNodeDataTypeBuilder::ASTNodeDataTypeBuilder(ASTNode& node) +{ + Assert(node.is_root()); + node.m_data_type = ASTNodeDataType::void_t; + + this->_buildNodeDataTypes(node); + + FunctionTable& function_table = node.m_symbol_table->functionTable(); + for (size_t function_id = 0; function_id < function_table.size(); ++function_id) { + FunctionDescriptor& function_descriptor = function_table[function_id]; + ASTNode& function_expression = function_descriptor.definitionNode(); + + this->_buildNodeDataTypes(function_expression); + } + + std::cout << " - build node data types\n"; +} diff --git a/src/language/ast/ASTNodeDataTypeBuilder.hpp b/src/language/ast/ASTNodeDataTypeBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..93643c82d80c9c222cb12b482416a661ff20fb31 --- /dev/null +++ b/src/language/ast/ASTNodeDataTypeBuilder.hpp @@ -0,0 +1,17 @@ +#ifndef AST_NODE_DATA_TYPE_BUILDER_HPP +#define AST_NODE_DATA_TYPE_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTNodeDataTypeBuilder +{ + private: + ASTNodeDataType _buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNode& name_node) const; + + void _buildNodeDataTypes(ASTNode& node) const; + + public: + ASTNodeDataTypeBuilder(ASTNode& root_node); +}; + +#endif // AST_NODE_DATA_TYPE_BUILDER_HPP diff --git a/src/language/ast/ASTNodeDataTypeChecker.cpp b/src/language/ast/ASTNodeDataTypeChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87ecba522b17666aa5ce1610f1caf54ce0db15e3 --- /dev/null +++ b/src/language/ast/ASTNodeDataTypeChecker.cpp @@ -0,0 +1,20 @@ +#include <language/ast/ASTNodeDataTypeChecker.hpp> + +void +ASTNodeDataTypeChecker::_checkNodeDataTypes(const ASTNode& n) +{ + if (n.m_data_type == ASTNodeDataType::undefined_t) { + throw parse_error("unexpected error: undefined datatype for AST node for " + n.name(), n.begin()); + } + + for (const auto& child : n.children) { + this->_checkNodeDataTypes(*child); + } +} + +ASTNodeDataTypeChecker::ASTNodeDataTypeChecker(const ASTNode& node) +{ + Assert(node.is_root()); + this->_checkNodeDataTypes(node); + std::cout << " - checked node data types\n"; +} diff --git a/src/language/ast/ASTNodeDataTypeChecker.hpp b/src/language/ast/ASTNodeDataTypeChecker.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8e6c06d41990c83e6d06b6ba0b002896f17008f3 --- /dev/null +++ b/src/language/ast/ASTNodeDataTypeChecker.hpp @@ -0,0 +1,15 @@ +#ifndef AST_NODE_DATA_TYPE_CHECKER_HPP +#define AST_NODE_DATA_TYPE_CHECKER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTNodeDataTypeChecker +{ + private: + void _checkNodeDataTypes(const ASTNode& node); + + public: + ASTNodeDataTypeChecker(const ASTNode& root_node); +}; + +#endif // AST_NODE_DATA_TYPE_CHECKER_HPP diff --git a/src/language/ast/ASTNodeDataTypeFlattener.cpp b/src/language/ast/ASTNodeDataTypeFlattener.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f19ed6667be11f429e9ab08e24ea33e264323cdb --- /dev/null +++ b/src/language/ast/ASTNodeDataTypeFlattener.cpp @@ -0,0 +1,62 @@ +#include <language/ast/ASTNodeDataTypeFlattener.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/utils/FunctionTable.hpp> +#include <language/utils/SymbolTable.hpp> + +ASTNodeDataTypeFlattener::ASTNodeDataTypeFlattener(ASTNode& node, FlattenedDataTypeList& flattened_datatype_list) +{ + if (node.is_type<language::expression_list>() or node.is_type<language::function_argument_list>()) { + for (auto& child_node : node.children) { + ASTNodeDataTypeFlattener{*child_node, flattened_datatype_list}; + } + } else if (node.is_type<language::function_evaluation>()) { + if (node.m_data_type != ASTNodeDataType::typename_t) { + flattened_datatype_list.push_back({node.m_data_type, node}); + } else { + ASTNode& function_name_node = *node.children[0]; + + auto [i_function_symbol, found] = node.m_symbol_table->find(function_name_node.string(), node.begin()); + Assert(found); + + switch (i_function_symbol->attributes().dataType()) { + case ASTNodeDataType::function_t: { + uint64_t function_id = std::get<uint64_t>(i_function_symbol->attributes().value()); + + FunctionDescriptor& function_descriptor = node.m_symbol_table->functionTable()[function_id]; + + ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1]; + + for (auto& image_sub_domain : function_image_domain.children) { + ASTNodeDataType data_type = ASTNodeDataType::undefined_t; + + if (image_sub_domain->is_type<language::B_set>()) { + data_type = ASTNodeDataType::bool_t; + } else if (image_sub_domain->is_type<language::Z_set>()) { + data_type = ASTNodeDataType::int_t; + } else if (image_sub_domain->is_type<language::N_set>()) { + data_type = ASTNodeDataType::unsigned_int_t; + } else if (image_sub_domain->is_type<language::R_set>()) { + data_type = ASTNodeDataType::double_t; + } else if (image_sub_domain->is_type<language::vector_type>()) { + data_type = getVectorDataType(*image_sub_domain); + } else if (image_sub_domain->is_type<language::string_type>()) { + data_type = ASTNodeDataType::string_t; + } + + Assert(data_type != ASTNodeDataType::undefined_t); + flattened_datatype_list.push_back({data_type, node}); + } + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected function type", node.begin()); + } + // LCOV_EXCL_STOP + } + } + } else { + flattened_datatype_list.push_back({node.m_data_type, node}); + } +} diff --git a/src/language/ast/ASTNodeDataTypeFlattener.hpp b/src/language/ast/ASTNodeDataTypeFlattener.hpp new file mode 100644 index 0000000000000000000000000000000000000000..081a9491a585a27ea1e12cb11d03647bd6ac1920 --- /dev/null +++ b/src/language/ast/ASTNodeDataTypeFlattener.hpp @@ -0,0 +1,16 @@ +#ifndef AST_NODE_DATA_TYPE_FLATTENER_HPP +#define AST_NODE_DATA_TYPE_FLATTENER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeSubDataType.hpp> + +#include <vector> + +struct ASTNodeDataTypeFlattener +{ + using FlattenedDataTypeList = std::vector<ASTNodeSubDataType>; + + ASTNodeDataTypeFlattener(ASTNode& node, FlattenedDataTypeList& flattened_datatype); +}; + +#endif // AST_NODE_DATA_TYPE_FLATTENER_HPP diff --git a/src/language/ast/ASTNodeDeclarationToAffectationConverter.cpp b/src/language/ast/ASTNodeDeclarationToAffectationConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..368c8051c3c33b991dbba29618f7e38f6a42c700 --- /dev/null +++ b/src/language/ast/ASTNodeDeclarationToAffectationConverter.cpp @@ -0,0 +1,27 @@ +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> + +#include <language/PEGGrammar.hpp> +#include <utils/PugsAssert.hpp> + +void +ASTNodeDeclarationToAffectationConverter::_convertNodeDeclaration(ASTNode& n) +{ + if (n.is_type<language::var_declaration>()) { + if (n.children.size() == 4) { + n.children[0] = std::move(n.children[2]); + n.children[1] = std::move(n.children[3]); + n.children.resize(2); + n.set_type<language::eq_op>(); + } + } else { + for (auto& child : n.children) { + this->_convertNodeDeclaration(*child); + } + } +} + +ASTNodeDeclarationToAffectationConverter::ASTNodeDeclarationToAffectationConverter(ASTNode& n) +{ + Assert(n.is_root()); + this->_convertNodeDeclaration(n); +} diff --git a/src/language/ast/ASTNodeDeclarationToAffectationConverter.hpp b/src/language/ast/ASTNodeDeclarationToAffectationConverter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d0c236072176e50b719261e81a803b86f0a379c6 --- /dev/null +++ b/src/language/ast/ASTNodeDeclarationToAffectationConverter.hpp @@ -0,0 +1,15 @@ +#ifndef AST_NODE_DECLARATION_TO_AFFECTATION_CONVERTER_HPP +#define AST_NODE_DECLARATION_TO_AFFECTATION_CONVERTER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTNodeDeclarationToAffectationConverter +{ + private: + void _convertNodeDeclaration(ASTNode& node); + + public: + ASTNodeDeclarationToAffectationConverter(ASTNode& root_node); +}; + +#endif // AST_NODE_DECLARATION_TO_AFFECTATION_CONVERTER_HPP diff --git a/src/language/ast/ASTNodeEmptyBlockCleaner.cpp b/src/language/ast/ASTNodeEmptyBlockCleaner.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74d80107c5dde594d48698153d08a92f705d7b7c --- /dev/null +++ b/src/language/ast/ASTNodeEmptyBlockCleaner.cpp @@ -0,0 +1,37 @@ +#include <language/ast/ASTNodeEmptyBlockCleaner.hpp> + +#include <language/PEGGrammar.hpp> +#include <utils/PugsAssert.hpp> + +#include <stack> + +void +ASTNodeEmptyBlockCleaner::_removeEmptyBlockNode(ASTNode& n) +{ + for (auto& child : n.children) { + this->_removeEmptyBlockNode(*child); + } + + std::stack<size_t> empty_block_ids; + for (size_t i_child = 0; i_child < n.children.size(); ++i_child) { + if (n.children[i_child]->is_type<language::block>()) { + if (n.children[i_child]->children.size() == 0) + empty_block_ids.push(i_child); + } + } + + while (empty_block_ids.size() > 0) { + size_t i_removed = empty_block_ids.top(); + empty_block_ids.pop(); + for (size_t i = i_removed; i + 1 < n.children.size(); ++i) { + n.children[i] = std::move(n.children[i + 1]); + } + n.children.pop_back(); + } +} + +ASTNodeEmptyBlockCleaner::ASTNodeEmptyBlockCleaner(ASTNode& n) +{ + Assert(n.is_root()); + this->_removeEmptyBlockNode(n); +} diff --git a/src/language/ast/ASTNodeEmptyBlockCleaner.hpp b/src/language/ast/ASTNodeEmptyBlockCleaner.hpp new file mode 100644 index 0000000000000000000000000000000000000000..53399ce6f53299b3535a91311840f0c45a92aa20 --- /dev/null +++ b/src/language/ast/ASTNodeEmptyBlockCleaner.hpp @@ -0,0 +1,15 @@ +#ifndef AST_NODE_EMPTY_BLOCK_CLEANER_HPP +#define AST_NODE_EMPTY_BLOCK_CLEANER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTNodeEmptyBlockCleaner +{ + private: + void _removeEmptyBlockNode(ASTNode& node); + + public: + ASTNodeEmptyBlockCleaner(ASTNode& root_node); +}; + +#endif // AST_NODE_EMPTY_BLOCK_CLEANER_HPP diff --git a/src/language/ast/ASTNodeExpressionBuilder.cpp b/src/language/ast/ASTNodeExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b9a0efbcb206b164ad31d6db18b3ca3727e09f9 --- /dev/null +++ b/src/language/ast/ASTNodeExpressionBuilder.cpp @@ -0,0 +1,147 @@ +#include <language/ast/ASTNodeExpressionBuilder.hpp> + +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp> +#include <language/ast/ASTNodeBinaryOperatorExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp> +#include <language/ast/ASTNodeIncDecExpressionBuilder.hpp> +#include <language/ast/ASTNodeListAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeUnaryOperatorExpressionBuilder.hpp> +#include <language/node_processor/ASTNodeExpressionListProcessor.hpp> +#include <language/node_processor/ASTNodeListProcessor.hpp> +#include <language/node_processor/BreakProcessor.hpp> +#include <language/node_processor/ContinueProcessor.hpp> +#include <language/node_processor/DoWhileProcessor.hpp> +#include <language/node_processor/FakeProcessor.hpp> +#include <language/node_processor/ForProcessor.hpp> +#include <language/node_processor/IfProcessor.hpp> +#include <language/node_processor/LocalNameProcessor.hpp> +#include <language/node_processor/NameProcessor.hpp> +#include <language/node_processor/OStreamProcessor.hpp> +#include <language/node_processor/TupleToTinyVectorProcessor.hpp> +#include <language/node_processor/TupleToVectorProcessor.hpp> +#include <language/node_processor/ValueProcessor.hpp> +#include <language/node_processor/WhileProcessor.hpp> + +#include <language/PEGGrammar.hpp> + +void +ASTNodeExpressionBuilder::_buildExpression(ASTNode& n) +{ + if (n.is_type<language::block>()) { + n.m_node_processor = std::make_unique<ASTNodeListProcessor>(n); + } else if ((n.is_type<language::eq_op>() or n.is_type<language::multiplyeq_op>() or + n.is_type<language::divideeq_op>() or n.is_type<language::pluseq_op>() or + n.is_type<language::minuseq_op>())) { + if (n.children[0]->is_type<language::name_list>() or n.children[0]->is_type<language::lvalue_list>()) { + ASTNodeListAffectationExpressionBuilder{n}; + } else { + ASTNodeAffectationExpressionBuilder{n}; + } + + } else if (n.is_type<language::tuple_expression>()) { + n.m_node_processor = std::make_unique<TupleToVectorProcessor<ASTNodeExpressionListProcessor>>(n); + } else if (n.is_type<language::function_definition>()) { + n.m_node_processor = std::make_unique<FakeProcessor>(); + + } else if (n.is_type<language::function_evaluation>()) { + ASTNodeFunctionEvaluationExpressionBuilder{n}; + + } else if (n.is_type<language::subscript_expression>()) { + ASTNodeArraySubscriptExpressionBuilder{n}; + + } else if (n.is_type<language::real>()) { + n.m_node_processor = std::make_unique<ValueProcessor>(n); + } else if (n.is_type<language::integer>()) { + n.m_node_processor = std::make_unique<ValueProcessor>(n); + } else if (n.is_type<language::literal>()) { + n.m_node_processor = std::make_unique<ValueProcessor>(n); + } else if (n.is_type<language::true_kw>()) { + n.m_node_processor = std::make_unique<ValueProcessor>(n); + } else if (n.is_type<language::false_kw>()) { + n.m_node_processor = std::make_unique<ValueProcessor>(n); + + } else if ((n.is_type<language::function_argument_list>()) or (n.is_type<language::expression_list>())) { + n.m_node_processor = std::make_unique<ASTNodeExpressionListProcessor>(n); + + } else if (n.is_type<language::name_list>() or n.is_type<language::lvalue_list>()) { + n.m_node_processor = std::make_unique<FakeProcessor>(); + + } else if (n.is_type<language::name>()) { + // Dealing with contexts + auto [i_symbol, success] = n.m_symbol_table->find(n.string(), n.begin()); + if (i_symbol->attributes().hasLocalContext()) { + n.m_node_processor = std::make_unique<LocalNameProcessor>(n); + } else { + n.m_node_processor = std::make_unique<NameProcessor>(n); + } + } else if (n.is_type<language::unary_minus>() or n.is_type<language::unary_not>()) { + ASTNodeUnaryOperatorExpressionBuilder{n}; + + } else if (n.is_type<language::unary_minusminus>() or n.is_type<language::unary_plusplus>() or + n.is_type<language::post_minusminus>() or n.is_type<language::post_plusplus>()) { + ASTNodeIncDecExpressionBuilder{n}; + + } else if (n.is_type<language::multiply_op>() or n.is_type<language::divide_op>() or n.is_type<language::plus_op>() or + n.is_type<language::minus_op>() or n.is_type<language::or_op>() or n.is_type<language::and_op>() or + n.is_type<language::xor_op>() or n.is_type<language::greater_op>() or + n.is_type<language::greater_or_eq_op>() or n.is_type<language::lesser_op>() or + n.is_type<language::lesser_or_eq_op>() or n.is_type<language::eqeq_op>() or + n.is_type<language::not_eq_op>()) { + ASTNodeBinaryOperatorExpressionBuilder{n}; + + } else if (n.is_type<language::cout_kw>()) { + n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::cout); + } else if (n.is_type<language::cerr_kw>()) { + n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::cerr); + } else if (n.is_type<language::clog_kw>()) { + n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::clog); + } else if (n.is_type<language::if_statement>()) { + n.m_node_processor = std::make_unique<IfProcessor>(n); + } else if (n.is_type<language::statement_block>()) { + n.m_node_processor = std::make_unique<ASTNodeListProcessor>(n); + } else if (n.is_type<language::do_while_statement>()) { + n.m_node_processor = std::make_unique<DoWhileProcessor>(n); + } else if (n.is_type<language::while_statement>()) { + n.m_node_processor = std::make_unique<WhileProcessor>(n); + } else if (n.is_type<language::for_statement>()) { + n.m_node_processor = std::make_unique<ForProcessor>(n); + } else if (n.is_type<language::for_statement_block>()) { + n.m_node_processor = std::make_unique<ASTNodeListProcessor>(n); + } else if (n.is_type<language::for_init>()) { + n.m_node_processor = std::make_unique<FakeProcessor>(); + } else if (n.is_type<language::for_post>()) { + n.m_node_processor = std::make_unique<FakeProcessor>(); + } else if (n.is_type<language::for_test>()) { + n.m_node_processor = std::make_unique<ValueProcessor>(n); + } else if (n.is_type<language::break_kw>()) { + n.m_node_processor = std::make_unique<BreakProcessor>(); + } else if (n.is_type<language::continue_kw>()) { + n.m_node_processor = std::make_unique<ContinueProcessor>(); + } else { + std::ostringstream error_message; + error_message << "undefined node processor type '" << rang::fgB::red << n.name() << rang::fg::reset << "'"; + throw parse_error{error_message.str(), std::vector{n.begin()}}; + } + + for (auto& child : n.children) { + this->_buildExpression(*child); + } +} + +ASTNodeExpressionBuilder::ASTNodeExpressionBuilder(ASTNode& node) +{ + Assert(node.is_root()); + node.m_node_processor = std::make_unique<ASTNodeListProcessor>(node); + for (auto& child : node.children) { + this->_buildExpression(*child); + } + + // Build expressions of functions + FunctionTable& function_table = node.m_symbol_table->functionTable(); + for (size_t function_id = 0; function_id < function_table.size(); ++function_id) { + FunctionDescriptor& function_descriptor = function_table[function_id]; + ASTNode& function_expression = function_descriptor.definitionNode(); + this->_buildExpression(function_expression); + } +} diff --git a/src/language/ast/ASTNodeExpressionBuilder.hpp b/src/language/ast/ASTNodeExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..74a2f720970df49a6ca5315dfd0b20fb2905f7d7 --- /dev/null +++ b/src/language/ast/ASTNodeExpressionBuilder.hpp @@ -0,0 +1,14 @@ +#ifndef AST_NODE_EXPRESSION_BUILDER_HPP +#define AST_NODE_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTNodeExpressionBuilder +{ + void _buildExpression(ASTNode& n); + + public: + ASTNodeExpressionBuilder(ASTNode& n); +}; + +#endif // AST_NODE_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5eb2ed3b0defeb35d47cd6f8e6812f2f82319883 --- /dev/null +++ b/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.cpp @@ -0,0 +1,27 @@ +#include <language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp> + +#include <language/ast/ASTNodeBuiltinFunctionExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionExpressionBuilder.hpp> +#include <language/utils/SymbolTable.hpp> + +ASTNodeFunctionEvaluationExpressionBuilder::ASTNodeFunctionEvaluationExpressionBuilder(ASTNode& node) +{ + auto [i_function_symbol, found] = node.m_symbol_table->find(node.children[0]->string(), node.begin()); + Assert(found); + + switch (i_function_symbol->attributes().dataType()) { + case ASTNodeDataType::function_t: { + ASTNodeFunctionExpressionBuilder{node}; + break; + } + case ASTNodeDataType::builtin_function_t: { + ASTNodeBuiltinFunctionExpressionBuilder{node}; + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected function type", node.begin()); + } + // LCOV_EXCL_STOP + } +} diff --git a/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp b/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5e474f11d06f92a4f1b187a4f850988ee100710c --- /dev/null +++ b/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_FUNCTION_EVALUATION_EXPRESSION_BUILDER_HPP +#define AST_NODE_FUNCTION_EVALUATION_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +struct ASTNodeFunctionEvaluationExpressionBuilder +{ + ASTNodeFunctionEvaluationExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_FUNCTION_EVALUATION_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2369940873394a33db2718a7ff42fe4870cffc2 --- /dev/null +++ b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp @@ -0,0 +1,449 @@ +#include <language/ast/ASTNodeFunctionExpressionBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNodeDataTypeFlattener.hpp> +#include <language/ast/ASTNodeNaturalConversionChecker.hpp> +#include <language/node_processor/FunctionProcessor.hpp> +#include <language/node_processor/TupleToTinyVectorProcessor.hpp> +#include <language/utils/FunctionTable.hpp> +#include <language/utils/SymbolTable.hpp> + +template <typename SymbolType> +std::unique_ptr<IFunctionArgumentConverter> +ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_symbol, + const ASTNodeSubDataType& node_sub_data_type) +{ + const size_t parameter_id = std::get<size_t>(parameter_symbol.attributes().value()); + + ASTNodeNaturalConversionChecker{node_sub_data_type, parameter_symbol.attributes().dataType()}; + + auto get_function_argument_converter_for = + [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> { + using ParameterT = std::decay_t<decltype(parameter_v)>; + switch (node_sub_data_type.m_data_type) { + case ASTNodeDataType::bool_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, bool>>(parameter_id); + } + case ASTNodeDataType::unsigned_int_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, uint64_t>>(parameter_id); + } + case ASTNodeDataType::int_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, int64_t>>(parameter_id); + } + case ASTNodeDataType::double_t: { + return std::make_unique<FunctionArgumentConverter<ParameterT, double>>(parameter_id); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid argument type 0", + std::vector{node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_argument_converter_for_vector = + [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> { + using ParameterT = std::decay_t<decltype(parameter_v)>; + switch (node_sub_data_type.m_data_type) { + case ASTNodeDataType::vector_t: { + if (node_sub_data_type.m_data_type.dimension() == parameter_v.dimension()) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(parameter_id); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid argument dimension", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::list_t: { + if (node_sub_data_type.m_parent_node.children.size() == parameter_v.dimension()) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(parameter_id); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid argument dimension", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::int_t: { + if (node_sub_data_type.m_parent_node.is_type<language::integer>()) { + if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ZeroType>>(parameter_id); + } + } + [[fallthrough]]; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid argument type", + std::vector{node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_argument_converter_for_string = [&]() -> std::unique_ptr<IFunctionArgumentConverter> { + return std::make_unique<FunctionArgumentToStringConverter>(parameter_id); + }; + + auto get_function_argument_converter_for_parameter_type = [&]() { + switch (parameter_symbol.attributes().dataType()) { + case ASTNodeDataType::bool_t: { + return get_function_argument_converter_for(bool{}); + } + case ASTNodeDataType::unsigned_int_t: { + return get_function_argument_converter_for(uint64_t{}); + } + case ASTNodeDataType::int_t: { + return get_function_argument_converter_for(int64_t{}); + } + case ASTNodeDataType::double_t: { + return get_function_argument_converter_for(double{}); + } + case ASTNodeDataType::string_t: { + return get_function_argument_converter_for_string(); + } + case ASTNodeDataType::vector_t: { + switch (parameter_symbol.attributes().dataType().dimension()) { + case 1: { + return get_function_argument_converter_for_vector(TinyVector<1>{}); + } + case 2: { + return get_function_argument_converter_for_vector(TinyVector<2>{}); + } + case 3: { + return get_function_argument_converter_for_vector(TinyVector<3>{}); + } + } + [[fallthrough]]; + } + + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined parameter type", std::vector{m_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + return get_function_argument_converter_for_parameter_type(); +} + +void +ASTNodeFunctionExpressionBuilder::_storeArgumentConverter(ASTNode& parameter_variable, + ASTNodeSubDataType& node_sub_data_type, + FunctionProcessor& function_processor) +{ + Assert(parameter_variable.is_type<language::name>(), "unexpected parameter type!"); + + auto [i_parameter_symbol, found] = + parameter_variable.m_symbol_table->find(parameter_variable.string(), parameter_variable.begin()); + Assert(found); + + function_processor.addArgumentConverter(this->_getArgumentConverter(*i_parameter_symbol, node_sub_data_type)); +} + +std::unique_ptr<FunctionProcessor> +ASTNodeFunctionExpressionBuilder::_buildArgumentConverter(FunctionDescriptor& function_descriptor, ASTNode& node) +{ + ASTNode& function_expression = *function_descriptor.definitionNode().children[1]; + + Assert(function_expression.m_symbol_table->hasContext()); + const SymbolTable::Context& context = function_expression.m_symbol_table->context(); + + const ASTNode& definition_node = function_descriptor.definitionNode(); + ASTNode& parameter_variables = *definition_node.children[0]; + + ASTNode& argument_nodes = *node.children[1]; + + std::unique_ptr function_processor = std::make_unique<FunctionProcessor>(argument_nodes, context); + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list; + ASTNodeDataTypeFlattener{argument_nodes, flattened_datatype_list}; + + const size_t arguments_number = flattened_datatype_list.size(); + + const size_t parameters_number = + parameter_variables.is_type<language::name_list>() ? parameter_variables.children.size() : 1; + + if (arguments_number != parameters_number) { + std::ostringstream error_message; + error_message << "bad number of arguments: expecting " << rang::fgB::yellow << parameters_number + << rang::style::reset << ", provided " << rang::fgB::yellow << arguments_number << rang::style::reset; + throw parse_error(error_message.str(), argument_nodes.begin()); + } + + if (arguments_number > 1) { + for (size_t i = 0; i < arguments_number; ++i) { + ASTNode& parameter_variable = *parameter_variables.children[i]; + this->_storeArgumentConverter(parameter_variable, flattened_datatype_list[i], *function_processor); + } + } else { + this->_storeArgumentConverter(parameter_variables, flattened_datatype_list[0], *function_processor); + } + + return function_processor; +} + +std::unique_ptr<INodeProcessor> +ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& return_value_type, + ASTNode& node, + ASTNode& function_component_expression) +{ + auto get_function_processor_for_expression_value = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> { + using ReturnT = std::decay_t<decltype(return_v)>; + switch (function_component_expression.m_data_type) { + case ASTNodeDataType::bool_t: { + return std::make_unique<FunctionExpressionProcessor<ReturnT, bool>>(function_component_expression); + } + case ASTNodeDataType::unsigned_int_t: { + return std::make_unique<FunctionExpressionProcessor<ReturnT, uint64_t>>(function_component_expression); + } + case ASTNodeDataType::int_t: { + return std::make_unique<FunctionExpressionProcessor<ReturnT, int64_t>>(function_component_expression); + } + case ASTNodeDataType::double_t: { + return std::make_unique<FunctionExpressionProcessor<ReturnT, double>>(function_component_expression); + } + case ASTNodeDataType::string_t: { + if constexpr (std::is_same_v<ReturnT, std::string>) { + return std::make_unique<FunctionExpressionProcessor<ReturnT, std::string>>(function_component_expression); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid string conversion", std::vector{node.children[1]->begin()}); + // LCOV_EXCL_STOP + } + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined expression value type for function", + std::vector{node.children[1]->begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_processor_for_expression_vector = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> { + using ReturnT = std::decay_t<decltype(return_v)>; + switch (function_component_expression.m_data_type) { + case ASTNodeDataType::vector_t: { + if (function_component_expression.m_data_type.dimension() == return_v.dimension()) { + return std::make_unique<FunctionExpressionProcessor<ReturnT, ReturnT>>(function_component_expression); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid dimension for returned vector", + std::vector{function_component_expression.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::list_t: { + if (function_component_expression.children.size() == return_v.dimension()) { + return std::make_unique<FunctionExpressionProcessor<ReturnT, AggregateDataVariant>>( + function_component_expression); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid dimension for returned vector", + std::vector{function_component_expression.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::int_t: { + if (function_component_expression.is_type<language::integer>()) { + if (std::stoi(function_component_expression.string()) == 0) { + return std::make_unique<FunctionExpressionProcessor<ReturnT, ZeroType>>(function_component_expression); + } + } + // LCOV_EXCL_START + throw parse_error("unexpected error: undefined expression value type for function", + std::vector{function_component_expression.begin()}); + // LCOV_EXCL_STOP + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined expression value type for function", + std::vector{function_component_expression.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto get_function_processor_for_value = [&]() { + switch (return_value_type) { + case ASTNodeDataType::bool_t: { + return get_function_processor_for_expression_value(bool{}); + } + case ASTNodeDataType::unsigned_int_t: { + return get_function_processor_for_expression_value(uint64_t{}); + } + case ASTNodeDataType::int_t: { + return get_function_processor_for_expression_value(int64_t{}); + } + case ASTNodeDataType::double_t: { + return get_function_processor_for_expression_value(double{}); + } + case ASTNodeDataType::vector_t: { + switch (return_value_type.dimension()) { + case 1: { + if (function_component_expression.m_data_type == ASTNodeDataType::vector_t) { + return get_function_processor_for_expression_vector(TinyVector<1>{}); + } else { + return get_function_processor_for_expression_value(TinyVector<1>{}); + } + } + case 2: { + return get_function_processor_for_expression_vector(TinyVector<2>{}); + } + case 3: { + return get_function_processor_for_expression_vector(TinyVector<3>{}); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid dimension in returned type", std::vector{node.begin()}); + } + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::string_t: { + return get_function_processor_for_expression_value(std::string{}); + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined return type for function", std::vector{node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + return get_function_processor_for_value(); +} + +ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node) : m_node(node) +{ + auto [i_function_symbol, found] = node.m_symbol_table->find(node.children[0]->string(), node.begin()); + Assert(found); + Assert(i_function_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + uint64_t function_id = std::get<uint64_t>(i_function_symbol->attributes().value()); + + FunctionDescriptor& function_descriptor = node.m_symbol_table->functionTable()[function_id]; + + std::unique_ptr function_processor = this->_buildArgumentConverter(function_descriptor, node); + + auto add_component_expression = [&](ASTNode& expression_node, ASTNode& domain_node) { + ASTNodeDataType return_value_type = ASTNodeDataType::undefined_t; + + ASTNode& image_domain_node = domain_node; + + if (image_domain_node.is_type<language::B_set>()) { + return_value_type = ASTNodeDataType::bool_t; + } else if (image_domain_node.is_type<language::Z_set>()) { + return_value_type = ASTNodeDataType::int_t; + } else if (image_domain_node.is_type<language::N_set>()) { + return_value_type = ASTNodeDataType::unsigned_int_t; + } else if (image_domain_node.is_type<language::R_set>()) { + return_value_type = ASTNodeDataType::double_t; + } else if (image_domain_node.is_type<language::vector_type>()) { + return_value_type = getVectorDataType(image_domain_node); + } else if (image_domain_node.is_type<language::string_type>()) { + return_value_type = ASTNodeDataType::string_t; + } + + Assert(return_value_type != ASTNodeDataType::undefined_t); + + if ((return_value_type == ASTNodeDataType::vector_t) and (return_value_type.dimension() == 1)) { + ASTNodeNaturalConversionChecker{expression_node, ASTNodeDataType::double_t}; + } else { + ASTNodeNaturalConversionChecker{expression_node, return_value_type}; + } + + function_processor->addFunctionExpressionProcessor( + this->_getFunctionProcessor(return_value_type, node, expression_node)); + }; + + ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1]; + ASTNode& function_expression = *function_descriptor.definitionNode().children[1]; + + if (function_image_domain.is_type<language::vector_type>()) { + ASTNodeDataType vector_type = getVectorDataType(function_image_domain); + + if ((vector_type.dimension() == 1) and (function_expression.m_data_type != ASTNodeDataType::vector_t)) { + ASTNodeNaturalConversionChecker{function_expression, ASTNodeDataType::double_t}; + } else { + ASTNodeNaturalConversionChecker{function_expression, vector_type}; + } + if (function_expression.is_type<language::expression_list>()) { + Assert(vector_type.dimension() == function_expression.children.size()); + + for (size_t i = 0; i < vector_type.dimension(); ++i) { + function_processor->addFunctionExpressionProcessor( + this->_getFunctionProcessor(ASTNodeDataType::double_t, node, *function_expression.children[i])); + } + + switch (vector_type.dimension()) { + case 2: { + node.m_node_processor = + std::make_unique<TupleToTinyVectorProcessor<FunctionProcessor, 2>>(node, std::move(function_processor)); + break; + } + case 3: { + node.m_node_processor = + std::make_unique<TupleToTinyVectorProcessor<FunctionProcessor, 3>>(node, std::move(function_processor)); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector_t dimension", std::vector{node.begin()}); + } + // LCOV_EXCL_STOP + } + } else if (function_expression.is_type<language::integer>()) { + if (std::stoi(function_expression.string()) == 0) { + switch (vector_type.dimension()) { + case 1: { + node.m_node_processor = + std::make_unique<FunctionExpressionProcessor<TinyVector<1>, ZeroType>>(function_expression); + break; + } + case 2: { + node.m_node_processor = + std::make_unique<FunctionExpressionProcessor<TinyVector<2>, ZeroType>>(function_expression); + break; + } + case 3: { + node.m_node_processor = + std::make_unique<FunctionExpressionProcessor<TinyVector<3>, ZeroType>>(function_expression); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector_t dimension", std::vector{node.begin()}); + } + // LCOV_EXCL_STOP + } + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: expecting 0", std::vector{function_expression.begin()}); + // LCOV_EXCL_STOP + } + } else { + function_processor->addFunctionExpressionProcessor( + this->_getFunctionProcessor(vector_type, node, function_expression)); + + node.m_node_processor = std::move(function_processor); + } + + } else { + if (function_expression.is_type<language::expression_list>()) { + ASTNode& image_domain_node = function_image_domain; + + for (size_t i = 0; i < function_expression.children.size(); ++i) { + add_component_expression(*function_expression.children[i], *image_domain_node.children[i]); + } + } else { + add_component_expression(function_expression, function_image_domain); + } + + node.m_node_processor = std::move(function_processor); + } +} diff --git a/src/language/ast/ASTNodeFunctionExpressionBuilder.hpp b/src/language/ast/ASTNodeFunctionExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..254f11dc837816dfd2abab0ea3b1431b5e20d852 --- /dev/null +++ b/src/language/ast/ASTNodeFunctionExpressionBuilder.hpp @@ -0,0 +1,35 @@ +#ifndef AST_NODE_FUNCTION_EXPRESSION_BUILDER_HPP +#define AST_NODE_FUNCTION_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeSubDataType.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class FunctionProcessor; +class FunctionDescriptor; +class IFunctionArgumentConverter; + +class ASTNodeFunctionExpressionBuilder +{ + private: + ASTNode& m_node; + + template <typename SymbolType> + std::unique_ptr<IFunctionArgumentConverter> _getArgumentConverter(SymbolType& parameter_symbol, + const ASTNodeSubDataType& node_sub_data_type); + + void _storeArgumentConverter(ASTNode& parameter_variable, + ASTNodeSubDataType& node_sub_data_type, + FunctionProcessor& function_processor); + + std::unique_ptr<FunctionProcessor> _buildArgumentConverter(FunctionDescriptor& function_descriptor, ASTNode& node); + + std::unique_ptr<INodeProcessor> _getFunctionProcessor(const ASTNodeDataType& return_value_type, + ASTNode& node, + ASTNode& function_component_expression); + + public: + ASTNodeFunctionExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_FUNCTION_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeIncDecExpressionBuilder.cpp b/src/language/ast/ASTNodeIncDecExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5eccdfcf61c597f97be00afcb688e3da857a220 --- /dev/null +++ b/src/language/ast/ASTNodeIncDecExpressionBuilder.cpp @@ -0,0 +1,53 @@ +#include <language/ast/ASTNodeIncDecExpressionBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/IncDecExpressionProcessor.hpp> + +ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n) +{ + auto set_inc_dec_operator_processor = [](ASTNode& n, const auto& operator_v) { + auto set_inc_dec_processor_for_value = [&](const ASTNodeDataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + switch (data_type) { + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, double>>(n); + break; + } + default: { + throw parse_error("unexpected error: undefined data type for unary operator", std::vector{n.begin()}); + } + } + }; + + if (not n.children[0]->is_type<language::name>()) { + if (n.children[0]->is_type<language::post_minusminus>() or n.children[0]->is_type<language::post_plusplus>() or + n.children[0]->is_type<language::unary_minusminus>() or n.children[0]->is_type<language::unary_plusplus>()) { + throw parse_error("chaining ++ or -- operators is not allowed", std::vector{n.children[0]->begin()}); + } else { + throw parse_error("invalid operand type for unary operator", std::vector{n.children[0]->begin()}); + } + } + + set_inc_dec_processor_for_value(n.m_data_type); + }; + + if (n.is_type<language::unary_minusminus>()) { + set_inc_dec_operator_processor(n, language::unary_minusminus{}); + } else if (n.is_type<language::unary_plusplus>()) { + set_inc_dec_operator_processor(n, language::unary_plusplus{}); + } else if (n.is_type<language::post_minusminus>()) { + set_inc_dec_operator_processor(n, language::post_minusminus{}); + } else if (n.is_type<language::post_plusplus>()) { + set_inc_dec_operator_processor(n, language::post_plusplus{}); + } else { + throw parse_error("unexpected error: undefined increment/decrement operator", std::vector{n.begin()}); + } +} diff --git a/src/language/ast/ASTNodeIncDecExpressionBuilder.hpp b/src/language/ast/ASTNodeIncDecExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..91c54c7bbf583142180666d6ca2b739477b0d70a --- /dev/null +++ b/src/language/ast/ASTNodeIncDecExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_INC_DEC_EXPRESSION_BUILDER_HPP +#define AST_NODE_INC_DEC_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +struct ASTNodeIncDecExpressionBuilder +{ + ASTNodeIncDecExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_INC_DEC_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeJumpPlacementChecker.cpp b/src/language/ast/ASTNodeJumpPlacementChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c699d8dce4866cd229c46c9cd8ab3dde513226f6 --- /dev/null +++ b/src/language/ast/ASTNodeJumpPlacementChecker.cpp @@ -0,0 +1,31 @@ +#include <language/ast/ASTNodeJumpPlacementChecker.hpp> + +#include <language/PEGGrammar.hpp> + +void +ASTNodeJumpPlacementChecker::_checkJumpPlacement(ASTNode& n, bool is_inside_loop) +{ + if (n.is_type<language::for_statement>() or n.is_type<language::do_while_statement>() or + n.is_type<language::while_statement>()) { + for (auto& child : n.children) { + this->_checkJumpPlacement(*child, true); + } + } else if (n.is_type<language::break_kw>() or n.is_type<language::continue_kw>()) { + if (not is_inside_loop) { + std::ostringstream error_message; + error_message << "unexpected '" << rang::fgB::red << n.string() << rang::fg::reset + << "' outside of loop or switch statement"; + throw parse_error(error_message.str(), std::vector{n.begin()}); + } + } else { + for (auto& child : n.children) { + this->_checkJumpPlacement(*child, is_inside_loop); + } + } +} + +ASTNodeJumpPlacementChecker::ASTNodeJumpPlacementChecker(ASTNode& n) +{ + Assert(n.is_root()); + this->_checkJumpPlacement(n, false); +} diff --git a/src/language/ast/ASTNodeJumpPlacementChecker.hpp b/src/language/ast/ASTNodeJumpPlacementChecker.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a880a79c5ec3211ffa6bdba4c8ff27a71ea5c5ed --- /dev/null +++ b/src/language/ast/ASTNodeJumpPlacementChecker.hpp @@ -0,0 +1,15 @@ +#ifndef AST_NODE_JUMP_PLACEMENT_CHECKER_HPP +#define AST_NODE_JUMP_PLACEMENT_CHECKER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTNodeJumpPlacementChecker +{ + private: + void _checkJumpPlacement(ASTNode& node, bool is_inside_loop); + + public: + ASTNodeJumpPlacementChecker(ASTNode& root_node); +}; + +#endif // AST_NODE_JUMP_PLACEMENT_CHECKER_HPP diff --git a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48b7e4f5ddacd4b788ff38bf0bceb82442230f70 --- /dev/null +++ b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp @@ -0,0 +1,242 @@ +#include <language/ast/ASTNodeListAffectationExpressionBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNodeDataTypeFlattener.hpp> +#include <language/ast/ASTNodeNaturalConversionChecker.hpp> +#include <language/node_processor/AffectationProcessor.hpp> + +template <typename OperatorT> +void +ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor( + const ASTNodeSubDataType& rhs_node_sub_data_type, + ASTNode& value_node, + std::unique_ptr<ListAffectationProcessor<OperatorT>>& list_affectation_processor) +{ + auto add_affectation_processor_for_data = [&](const auto& value, const ASTNodeSubDataType& node_sub_data_type) { + using ValueT = std::decay_t<decltype(value)>; + switch (node_sub_data_type.m_data_type) { + case ASTNodeDataType::bool_t: { + list_affectation_processor->template add<ValueT, bool>(value_node); + break; + } + case ASTNodeDataType::unsigned_int_t: { + list_affectation_processor->template add<ValueT, uint64_t>(value_node); + break; + } + case ASTNodeDataType::int_t: { + list_affectation_processor->template add<ValueT, int64_t>(value_node); + break; + } + case ASTNodeDataType::double_t: { + list_affectation_processor->template add<ValueT, double>(value_node); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid operand type for affectation", + std::vector{node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + auto add_affectation_processor_for_vector_data = [&](const auto& value, + const ASTNodeSubDataType& node_sub_data_type) { + using ValueT = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<ValueT, TinyVector<1>>) { + if ((node_sub_data_type.m_data_type == ASTNodeDataType::vector_t) and + (node_sub_data_type.m_data_type.dimension() == value.dimension())) { + list_affectation_processor->template add<ValueT, ValueT>(value_node); + } else { + add_affectation_processor_for_data(value, node_sub_data_type); + } + } else if constexpr (std::is_same_v<ValueT, TinyVector<2>> or std::is_same_v<ValueT, TinyVector<3>>) { + if ((node_sub_data_type.m_data_type == ASTNodeDataType::vector_t) and + (node_sub_data_type.m_data_type.dimension() == value.dimension())) { + list_affectation_processor->template add<ValueT, ValueT>(value_node); + } else if ((node_sub_data_type.m_data_type == ASTNodeDataType::list_t) and + (node_sub_data_type.m_parent_node.children.size() == value.dimension())) { + list_affectation_processor->template add<ValueT, AggregateDataVariant>(value_node); + } else if (node_sub_data_type.m_parent_node.is_type<language::integer>()) { + if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) { + list_affectation_processor->template add<ValueT, ZeroType>(value_node); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid operand value", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid dimension", std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } else { + throw parse_error("unexpected error: invalid value type", std::vector{node_sub_data_type.m_parent_node.begin()}); + } + }; + + auto add_affectation_processor_for_string_data = [&](const ASTNodeSubDataType& node_sub_data_type) { + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + switch (node_sub_data_type.m_data_type) { + case ASTNodeDataType::bool_t: { + list_affectation_processor->template add<std::string, bool>(value_node); + break; + } + case ASTNodeDataType::unsigned_int_t: { + list_affectation_processor->template add<std::string, uint64_t>(value_node); + break; + } + case ASTNodeDataType::int_t: { + list_affectation_processor->template add<std::string, int64_t>(value_node); + break; + } + case ASTNodeDataType::double_t: { + list_affectation_processor->template add<std::string, double>(value_node); + break; + } + case ASTNodeDataType::string_t: { + list_affectation_processor->template add<std::string, std::string>(value_node); + break; + } + case ASTNodeDataType::vector_t: { + switch (node_sub_data_type.m_data_type.dimension()) { + case 1: { + list_affectation_processor->template add<std::string, TinyVector<1>>(value_node); + break; + } + case 2: { + list_affectation_processor->template add<std::string, TinyVector<2>>(value_node); + break; + } + case 3: { + list_affectation_processor->template add<std::string, TinyVector<3>>(value_node); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector dimension", + std::vector{node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error:invalid operand type for string affectation", + std::vector{node_sub_data_type.m_parent_node.begin()}); + } + // LCOV_EXCL_STOP + } + } else { + throw parse_error("unexpected error: undefined operator type for string affectation", + std::vector{m_node.begin()}); + } + }; + + auto add_affectation_processor_for_value = [&](const ASTNodeDataType& value_type, + const ASTNodeSubDataType& node_sub_data_type) { + switch (value_type) { + case ASTNodeDataType::bool_t: { + add_affectation_processor_for_data(bool{}, node_sub_data_type); + break; + } + case ASTNodeDataType::unsigned_int_t: { + add_affectation_processor_for_data(uint64_t{}, node_sub_data_type); + break; + } + case ASTNodeDataType::int_t: { + add_affectation_processor_for_data(int64_t{}, node_sub_data_type); + break; + } + case ASTNodeDataType::double_t: { + add_affectation_processor_for_data(double{}, node_sub_data_type); + break; + } + case ASTNodeDataType::vector_t: { + switch (value_type.dimension()) { + case 1: { + add_affectation_processor_for_vector_data(TinyVector<1>{}, node_sub_data_type); + break; + } + case 2: { + add_affectation_processor_for_vector_data(TinyVector<2>{}, node_sub_data_type); + break; + } + case 3: { + add_affectation_processor_for_vector_data(TinyVector<3>{}, node_sub_data_type); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("invalid dimension", std::vector{value_node.begin()}); + } + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + add_affectation_processor_for_string_data(node_sub_data_type); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: undefined value type for tuple affectation", + std::vector{value_node.begin()}); + } + // LCOV_EXCL_STOP + } + }; + + if ((value_node.m_data_type != rhs_node_sub_data_type.m_data_type) and + (value_node.m_data_type == ASTNodeDataType::vector_t) and (value_node.m_data_type.dimension() == 1)) { + ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, ASTNodeDataType::double_t}; + } else { + ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, value_node.m_data_type}; + } + + add_affectation_processor_for_value(value_node.m_data_type, rhs_node_sub_data_type); +} + +template <typename OperatorT> +void +ASTNodeListAffectationExpressionBuilder::_buildListAffectationProcessor() +{ + Assert(m_node.children[1]->is_type<language::expression_list>() or + m_node.children[1]->is_type<language::function_evaluation>()); + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_rhs_data_type_list; + ASTNodeDataTypeFlattener{*m_node.children[1], flattened_rhs_data_type_list}; + + ASTNode& name_list_node = *m_node.children[0]; + + if (name_list_node.children.size() != flattened_rhs_data_type_list.size()) { + throw parse_error("incompatible list sizes in affectation", std::vector{m_node.begin()}); + } + + using ListAffectationProcessorT = ListAffectationProcessor<OperatorT>; + + std::unique_ptr list_affectation_processor = std::make_unique<ListAffectationProcessorT>(m_node); + + for (size_t i = 0; i < name_list_node.children.size(); ++i) { + ASTNode& name_node = *name_list_node.children[i]; + this->_buildAffectationProcessor(flattened_rhs_data_type_list[i], name_node, list_affectation_processor); + } + + m_node.m_node_processor = std::move(list_affectation_processor); +} + +ASTNodeListAffectationExpressionBuilder::ASTNodeListAffectationExpressionBuilder(ASTNode& node) : m_node(node) +{ + if (node.children[1]->is_type<language::expression_list>() or + node.children[1]->is_type<language::function_evaluation>()) { + if (node.is_type<language::eq_op>()) { + this->_buildListAffectationProcessor<language::eq_op>(); + } else { + throw parse_error("undefined affectation operator for tuples", std::vector{node.begin()}); + } + } else { + throw parse_error("invalid right hand side in tuple affectation", std::vector{node.children[1]->begin()}); + } +} diff --git a/src/language/ast/ASTNodeListAffectationExpressionBuilder.hpp b/src/language/ast/ASTNodeListAffectationExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..50aaf94d27d364ecb5f40a3b125e09470c4b9d56 --- /dev/null +++ b/src/language/ast/ASTNodeListAffectationExpressionBuilder.hpp @@ -0,0 +1,27 @@ +#ifndef AST_NODE_LIST_AFFECTATION_EXPRESSION_BUILDER_HPP +#define AST_NODE_LIST_AFFECTATION_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeSubDataType.hpp> + +template <typename OperatorT> +class ListAffectationProcessor; + +class ASTNodeListAffectationExpressionBuilder +{ + private: + ASTNode& m_node; + + template <typename OperatorT> + void _buildAffectationProcessor(const ASTNodeSubDataType& rhs_node_sub_data_type, + ASTNode& value_node, + std::unique_ptr<ListAffectationProcessor<OperatorT>>& list_affectation_processor); + + template <typename OperatorT> + void _buildListAffectationProcessor(); + + public: + ASTNodeListAffectationExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_LIST_AFFECTATION_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTNodeNaturalConversionChecker.cpp b/src/language/ast/ASTNodeNaturalConversionChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b01ff1fc346856797b37f58a20b72039e8b49f59 --- /dev/null +++ b/src/language/ast/ASTNodeNaturalConversionChecker.cpp @@ -0,0 +1,103 @@ +#include <language/ast/ASTNodeNaturalConversionChecker.hpp> + +#include <language/PEGGrammar.hpp> +#include <utils/Exceptions.hpp> + +void +ASTNodeNaturalConversionChecker::_checkIsNaturalTypeConversion(const ASTNode& node, + const ASTNodeDataType& data_type, + const ASTNodeDataType& target_data_type) const +{ + if (not isNaturalConversion(data_type, target_data_type)) { + std::ostringstream error_message; + error_message << "invalid implicit conversion: "; + error_message << rang::fgB::red << dataTypeName(data_type) << " -> " << dataTypeName(target_data_type) + << rang::fg::reset; + + if ((data_type == ASTNodeDataType::undefined_t) or (target_data_type == ASTNodeDataType::undefined_t)) { + throw UnexpectedError(error_message.str()); + } else { + throw parse_error(error_message.str(), node.begin()); + } + } +} + +void +ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNode& node, + const ASTNodeDataType& data_type, + const ASTNodeDataType& target_data_type) const +{ + if (target_data_type == ASTNodeDataType::vector_t) { + switch (node.m_data_type) { + case ASTNodeDataType::list_t: { + if (node.children.size() != target_data_type.dimension()) { + throw parse_error("incompatible dimensions in affectation", std::vector{node.begin()}); + } + for (const auto& child : node.children) { + this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, ASTNodeDataType::double_t); + } + + break; + } + case ASTNodeDataType::vector_t: { + if (data_type.dimension() != target_data_type.dimension()) { + throw parse_error("incompatible dimensions in affectation", std::vector{node.begin()}); + } + break; + } + case ASTNodeDataType::int_t: { + if (node.is_type<language::integer>()) { + if (std::stoi(node.string()) == 0) { + break; + } + } + [[fallthrough]]; + } + default: { + this->_checkIsNaturalTypeConversion(node, data_type, target_data_type); + } + } + } else if (target_data_type == ASTNodeDataType::tuple_t) { + const ASTNodeDataType& target_content_type = target_data_type.contentType(); + if (node.m_data_type == ASTNodeDataType::tuple_t) { + this->_checkIsNaturalExpressionConversion(node, data_type.contentType(), target_content_type); + } else if (node.m_data_type == ASTNodeDataType::list_t) { + if ((target_data_type.contentType() == ASTNodeDataType::vector_t) and + (target_data_type.contentType().dimension() == 1)) { + for (const auto& child : node.children) { + if (not isNaturalConversion(child->m_data_type, target_data_type)) { + this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, ASTNodeDataType::double_t); + } + } + } else { + for (const auto& child : node.children) { + this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, target_content_type); + } + } + } else { + if ((target_data_type.contentType() == ASTNodeDataType::vector_t) and + (target_data_type.contentType().dimension() == 1)) { + if (not isNaturalConversion(data_type, target_data_type)) { + this->_checkIsNaturalExpressionConversion(node, data_type, ASTNodeDataType::double_t); + } + } else { + this->_checkIsNaturalExpressionConversion(node, data_type, target_content_type); + } + } + } else { + this->_checkIsNaturalTypeConversion(node, data_type, target_data_type); + } +} + +ASTNodeNaturalConversionChecker::ASTNodeNaturalConversionChecker(const ASTNode& data_node, + const ASTNodeDataType& target_data_type) +{ + this->_checkIsNaturalExpressionConversion(data_node, data_node.m_data_type, target_data_type); +} + +ASTNodeNaturalConversionChecker::ASTNodeNaturalConversionChecker(const ASTNodeSubDataType& data_node_sub_data_type, + const ASTNodeDataType& target_data_type) +{ + this->_checkIsNaturalExpressionConversion(data_node_sub_data_type.m_parent_node, data_node_sub_data_type.m_data_type, + target_data_type); +} diff --git a/src/language/ast/ASTNodeNaturalConversionChecker.hpp b/src/language/ast/ASTNodeNaturalConversionChecker.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9d89e3b4925b6aaebfbc06c92fe30164e9b061fd --- /dev/null +++ b/src/language/ast/ASTNodeNaturalConversionChecker.hpp @@ -0,0 +1,26 @@ +#ifndef AST_NODE_NATURAL_CONVERSION_CHECKER_HPP +#define AST_NODE_NATURAL_CONVERSION_CHECKER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeDataType.hpp> +#include <language/ast/ASTNodeSubDataType.hpp> + +class ASTNodeNaturalConversionChecker +{ + private: + void _checkIsNaturalTypeConversion(const ASTNode& ast_node, + const ASTNodeDataType& data_type, + const ASTNodeDataType& target_data_type) const; + + void _checkIsNaturalExpressionConversion(const ASTNode& ast_node, + const ASTNodeDataType& data_type, + const ASTNodeDataType& target_data_type) const; + + public: + ASTNodeNaturalConversionChecker(const ASTNode& data_node, const ASTNodeDataType& target_data_type); + + ASTNodeNaturalConversionChecker(const ASTNodeSubDataType& data_node_sub_data_type, + const ASTNodeDataType& target_data_type); +}; + +#endif // AST_NODE_NATURAL_CONVERSION_CHECKER_HPP diff --git a/src/language/ast/ASTNodeSubDataType.hpp b/src/language/ast/ASTNodeSubDataType.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7844d367ae686fe88e05bc119d198288eca45c6 --- /dev/null +++ b/src/language/ast/ASTNodeSubDataType.hpp @@ -0,0 +1,13 @@ +#ifndef AST_NODE_SUB_DATA_TYPE_HPP +#define AST_NODE_SUB_DATA_TYPE_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeDataType.hpp> + +struct ASTNodeSubDataType +{ + ASTNodeDataType m_data_type; + ASTNode& m_parent_node; +}; + +#endif // AST_NODE_SUB_DATA_TYPE_HPP diff --git a/src/language/ast/ASTNodeTypeCleaner.hpp b/src/language/ast/ASTNodeTypeCleaner.hpp new file mode 100644 index 0000000000000000000000000000000000000000..46e516abbd4bc4145e31ecf5c15d9e0cbcdc272a --- /dev/null +++ b/src/language/ast/ASTNodeTypeCleaner.hpp @@ -0,0 +1,46 @@ +#ifndef AST_NODE_DECLARATION_CLEANER_HPP +#define AST_NODE_DECLARATION_CLEANER_HPP + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <utils/PugsAssert.hpp> + +#include <stack> + +template <typename NodeType> +class ASTNodeTypeCleaner +{ + private: + void + _removeDeclarationNode(ASTNode& node) + { + std::stack<size_t> declaration_ids; + for (size_t i_child = 0; i_child < node.children.size(); ++i_child) { + if (node.children[i_child]->is_type<NodeType>()) { + declaration_ids.push(i_child); + } + } + + while (declaration_ids.size() > 0) { + size_t i_removed = declaration_ids.top(); + declaration_ids.pop(); + for (size_t i = i_removed; i + 1 < node.children.size(); ++i) { + node.children[i] = std::move(node.children[i + 1]); + } + node.children.pop_back(); + } + + for (auto& child : node.children) { + this->_removeDeclarationNode(*child); + } + } + + public: + ASTNodeTypeCleaner(ASTNode& root_node) + { + Assert(root_node.is_root()); + this->_removeDeclarationNode(root_node); + } +}; + +#endif // AST_NODE_DECLARATION_CLEANER_HPP diff --git a/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.cpp b/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff081cea9e53378c6ea3639e3b7fd0a7b9162ca3 --- /dev/null +++ b/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.cpp @@ -0,0 +1,99 @@ +#include <language/ast/ASTNodeUnaryOperatorExpressionBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/UnaryExpressionProcessor.hpp> + +ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(ASTNode& n) +{ + auto set_unary_operator_processor = [](ASTNode& n, const auto& operator_v) { + using OperatorT = std::decay_t<decltype(operator_v)>; + + auto set_unary_operator_processor_for_data = [&](const auto& value, const ASTNodeDataType& data_type) { + using ValueT = std::decay_t<decltype(value)>; + switch (data_type) { + case ASTNodeDataType::bool_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, bool>>(n); + break; + } + case ASTNodeDataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, uint64_t>>(n); + break; + } + case ASTNodeDataType::int_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, int64_t>>(n); + break; + } + case ASTNodeDataType::double_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, double>>(n); + break; + } + default: { + throw parse_error("unexpected error: invalid operand type for unary operator", + std::vector{n.children[0]->begin()}); + } + } + }; + + auto set_unary_operator_processor_for_value = [&](const ASTNodeDataType& value_type) { + const ASTNodeDataType data_type = n.children[0]->m_data_type; + switch (value_type) { + case ASTNodeDataType::bool_t: { + set_unary_operator_processor_for_data(bool{}, data_type); + break; + } + case ASTNodeDataType::int_t: { + set_unary_operator_processor_for_data(int64_t{}, data_type); + break; + } + case ASTNodeDataType::double_t: { + set_unary_operator_processor_for_data(double{}, data_type); + break; + } + case ASTNodeDataType::vector_t: { + if constexpr (std::is_same_v<OperatorT, language::unary_minus>) { + switch (data_type.dimension()) { + case 1: { + using ValueT = TinyVector<1>; + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, ValueT>>(n); + break; + } + case 2: { + using ValueT = TinyVector<2>; + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, ValueT>>(n); + break; + } + case 3: { + using ValueT = TinyVector<3>; + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, ValueT>>(n); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector dimension", std::vector{n.begin()}); + } + // LCOV_EXCL_STOP + } + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid unary operator for vector data", std::vector{n.begin()}); + // LCOV_EXCL_STOP + } + break; + } + default: { + throw parse_error("undefined value type for unary operator", std::vector{n.begin()}); + } + } + }; + + set_unary_operator_processor_for_value(n.m_data_type); + }; + + if (n.is_type<language::unary_minus>()) { + set_unary_operator_processor(n, language::unary_minus{}); + } else if (n.is_type<language::unary_not>()) { + set_unary_operator_processor(n, language::unary_not{}); + } else { + throw parse_error("unexpected error: undefined unary operator", std::vector{n.begin()}); + } +} diff --git a/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.hpp b/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7000981e2c530a197233546d6cceb873f1ced4f8 --- /dev/null +++ b/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_UNARY_OPERATOR_EXPRESSION_BUILDER_HPP +#define AST_NODE_UNARY_OPERATOR_EXPRESSION_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> + +struct ASTNodeUnaryOperatorExpressionBuilder +{ + ASTNodeUnaryOperatorExpressionBuilder(ASTNode& node); +}; + +#endif // AST_NODE_UNARY_OPERATOR_EXPRESSION_BUILDER_HPP diff --git a/src/language/ast/ASTSymbolInitializationChecker.cpp b/src/language/ast/ASTSymbolInitializationChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b68e6d05a5872c95c546b108ad6ef8c9256e1965 --- /dev/null +++ b/src/language/ast/ASTSymbolInitializationChecker.cpp @@ -0,0 +1,132 @@ +#include <language/ast/ASTSymbolInitializationChecker.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/utils/SymbolTable.hpp> + +void +ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node) +{ + if (node.is_type<language::var_declaration>()) { + auto set_is_initialized = [&](ASTNode& name_node) { + const std::string& symbol = name_node.string(); + auto [i_symbol, found] = node.m_symbol_table->find(symbol, name_node.begin()); + Assert(found, "unexpected error, should have been detected through declaration checking"); + i_symbol->attributes().setIsInitialized(); + }; + + auto check_correct_name_in_definition = [](ASTNode& decl_name_node, ASTNode& def_name_node) { + if (def_name_node.is_type<language::name_list>()) { + throw parse_error("unexpected variable list, expecting one identifier", std::vector{def_name_node.begin()}); + } + Assert(def_name_node.is_type<language::name>()); + if (decl_name_node.string() != def_name_node.string()) { + std::ostringstream os; + os << "invalid identifier, expecting '" << decl_name_node.string() << "'" << std::ends; + throw parse_error(os.str(), std::vector{def_name_node.begin()}); + } + }; + + if (node.children[0]->is_type<language::name>()) { + if (node.children.size() == 4) { + this->_checkSymbolInitialization(*node.children[3]); + check_correct_name_in_definition(*node.children[0], *node.children[2]); + set_is_initialized(*node.children[0]); + } + } else if (node.children[0]->is_type<language::name_list>()) { + if (node.children.size() == 4) { + ASTNode& decl_name_list_node = *node.children[0]; + ASTNode& def_name_list_node = *node.children[2]; + Assert(def_name_list_node.is_type<language::name_list>()); + ASTNode& expression_list_node = *node.children[3]; + Assert(expression_list_node.is_type<language::expression_list>()); + + if (decl_name_list_node.children.size() != def_name_list_node.children.size()) { + std::ostringstream os; + os << "invalid number of definition identifiers, expecting " << decl_name_list_node.children.size() + << " found " << def_name_list_node.children.size() << std::ends; + throw parse_error(os.str(), std::vector{def_name_list_node.begin()}); + } + if (def_name_list_node.children.size() != expression_list_node.children.size()) { + std::ostringstream os; + os << "invalid number of definition expressions, expecting " << decl_name_list_node.children.size() + << " found " << expression_list_node.children.size() << std::ends; + throw parse_error(os.str(), std::vector{expression_list_node.begin()}); + } + + this->_checkSymbolInitialization(expression_list_node); + for (size_t i = 0; i < decl_name_list_node.children.size(); ++i) { + check_correct_name_in_definition(*decl_name_list_node.children[i], *def_name_list_node.children[i]); + set_is_initialized(*decl_name_list_node.children[i]); + } + } + } + } else if (node.is_type<language::fct_declaration>()) { + const std::string& symbol = node.children[0]->string(); + auto [i_symbol, found] = node.m_symbol_table->find(symbol, node.children[0]->begin()); + Assert(found, "unexpected error, should have been detected through declaration checking"); + + i_symbol->attributes().setIsInitialized(); + + auto& function_table = node.m_symbol_table->functionTable(); + + uint64_t function_id = std::get<uint64_t>(i_symbol->attributes().value()); + auto& function_descriptor = function_table[function_id]; + this->_checkSymbolInitialization(function_descriptor.definitionNode()); + + } else if (node.is_type<language::function_definition>()) { + this->_checkSymbolInitialization(*node.children[1]); + } else if (node.is_type<language::eq_op>()) { + // first checks for right hand side + this->_checkSymbolInitialization(*node.children[1]); + + auto set_is_initialized = [&](ASTNode& name_node) { + const std::string& symbol = name_node.string(); + auto [i_symbol, found] = node.m_symbol_table->find(symbol, name_node.begin()); + Assert(found, "unexpected error, should have been detected through declaration checking"); + i_symbol->attributes().setIsInitialized(); + }; + + if (node.children[0]->is_type<language::name>()) { + set_is_initialized(*node.children[0]); + } else if (node.children[0]->is_type<language::subscript_expression>()) { + ASTNode& subscript_node = *node.children[0]; + ASTNode& name_node = *subscript_node.children[0]; + + Assert(name_node.is_type<language::name>()); + set_is_initialized(name_node); + } else if (node.children[0]->is_type<language::name_list>() or node.children[0]->is_type<language::lvalue_list>()) { + ASTNode& list_node = *node.children[0]; + for (auto& child_node : list_node.children) { + if (child_node->is_type<language::name>()) { + set_is_initialized(*child_node); + } else { + Assert(child_node->is_type<language::subscript_expression>()); + ASTNode& name_node = *child_node->children[0]; + Assert(name_node.is_type<language::name>()); + set_is_initialized(name_node); + } + } + } + } else if (node.is_type<language::name>()) { + auto [i_symbol, found] = node.m_symbol_table->find(node.string(), node.begin()); + Assert(found, "unexpected error, should have been detected through declaration checking"); + if (not i_symbol->attributes().isInitialized()) { + std::ostringstream error_message; + error_message << "uninitialized symbol '" << rang::fg::red << node.string() << rang::fg::reset << '\''; + throw parse_error(error_message.str(), std::vector{node.begin()}); + } + } + + if (not(node.is_type<language::var_declaration>() or node.is_type<language::fct_declaration>() or + node.is_type<language::eq_op>())) { + for (auto& child : node.children) { + this->_checkSymbolInitialization(*child); + } + } +} + +ASTSymbolInitializationChecker::ASTSymbolInitializationChecker(ASTNode& root_node) +{ + Assert(root_node.is_root()); + this->_checkSymbolInitialization(root_node); +} diff --git a/src/language/ast/ASTSymbolInitializationChecker.hpp b/src/language/ast/ASTSymbolInitializationChecker.hpp new file mode 100644 index 0000000000000000000000000000000000000000..022ac764821fe374255f355681883ac4dc04605f --- /dev/null +++ b/src/language/ast/ASTSymbolInitializationChecker.hpp @@ -0,0 +1,15 @@ +#ifndef AST_SYMBOL_INITIALIZATION_CHECKER_HPP +#define AST_SYMBOL_INITIALIZATION_CHECKER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTSymbolInitializationChecker +{ + private: + void _checkSymbolInitialization(ASTNode& node); + + public: + ASTSymbolInitializationChecker(ASTNode& root_node); +}; + +#endif // AST_SYMBOL_INITIALIZATION_CHECKER_HPP diff --git a/src/language/ast/ASTSymbolTableBuilder.cpp b/src/language/ast/ASTSymbolTableBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c8f4850a5cd477eac43fb43c30d6eb0d7cca671 --- /dev/null +++ b/src/language/ast/ASTSymbolTableBuilder.cpp @@ -0,0 +1,104 @@ +#include <language/ast/ASTSymbolTableBuilder.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/utils/SymbolTable.hpp> + +void +ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>& symbol_table) +{ + if (n.is_type<language::block>() or (n.is_type<language::for_statement>())) { + if (!n.children.empty()) { + std::shared_ptr block_symbol_table = std::make_shared<SymbolTable>(symbol_table); + n.m_symbol_table = block_symbol_table; + + for (auto& child : n.children) { + this->buildSymbolTable(*child, block_symbol_table); + } + } + } else if (n.is_type<language::fct_declaration>()) { + std::shared_ptr local_symbol_table = + std::make_shared<SymbolTable>(symbol_table, std::make_shared<SymbolTable::Context>()); + + n.m_symbol_table = local_symbol_table; + const std::string& symbol = n.children[0]->string(); + auto [i_symbol, success] = symbol_table->add(symbol, n.children[0]->begin()); + if (not success) { + std::ostringstream error_message; + error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << "' was already defined!"; + throw parse_error(error_message.str(), std::vector{n.begin()}); + } + + for (auto& child : n.children) { + this->buildSymbolTable(*child, local_symbol_table); + } + + size_t function_id = + symbol_table->functionTable().add(FunctionDescriptor{symbol, std::move(n.children[1]), std::move(n.children[2])}); + i_symbol->attributes().value() = function_id; + n.children.resize(1); + } else { + n.m_symbol_table = symbol_table; + if (n.has_content()) { + if (n.is_type<language::var_declaration>()) { + auto register_symbol = [&](const ASTNode& argument_node) { + auto [i_symbol, success] = symbol_table->add(argument_node.string(), argument_node.begin()); + if (not success) { + std::ostringstream error_message; + error_message << "symbol '" << rang::fg::red << argument_node.string() << rang::fg::reset + << "' was already defined!"; + throw parse_error(error_message.str(), std::vector{argument_node.begin()}); + } + }; + + if (n.children[0]->is_type<language::name>()) { + register_symbol(*n.children[0]); + } else { // treats the case of list of parameters + Assert(n.children[0]->is_type<language::name_list>()); + for (auto& child : n.children[0]->children) { + register_symbol(*child); + } + } + } else if (n.is_type<language::function_definition>()) { + auto register_and_initialize_symbol = [&](const ASTNode& argument_node) { + auto [i_symbol, success] = symbol_table->add(argument_node.string(), argument_node.begin()); + if (not success) { + std::ostringstream error_message; + error_message << "symbol '" << rang::fg::red << argument_node.string() << rang::fg::reset + << "' was already defined!"; + throw parse_error(error_message.str(), std::vector{argument_node.begin()}); + } + // Symbols will be initialized at call + i_symbol->attributes().setIsInitialized(); + }; + + if (n.children[0]->is_type<language::name>()) { + register_and_initialize_symbol(*n.children[0]); + } else { // treats the case of list of parameters + Assert(n.children[0]->is_type<language::name_list>()); + for (auto& child : n.children[0]->children) { + register_and_initialize_symbol(*child); + } + } + } else if (n.is_type<language::name>()) { + auto [i_symbol, found] = symbol_table->find(n.string(), n.begin()); + if (not found) { + std::ostringstream error_message; + error_message << "undefined symbol '" << rang::fg::red << n.string() << rang::fg::reset << '\''; + throw parse_error(error_message.str(), std::vector{n.begin()}); + } + } + } + + for (auto& child : n.children) { + this->buildSymbolTable(*child, symbol_table); + } + } +} + +ASTSymbolTableBuilder::ASTSymbolTableBuilder(ASTNode& node) +{ + Assert(node.is_root()); + + this->buildSymbolTable(node, node.m_symbol_table); + std::cout << " - checked symbols declaration\n"; +} diff --git a/src/language/ast/ASTSymbolTableBuilder.hpp b/src/language/ast/ASTSymbolTableBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7929f7ab1ea43296bc3e56295e0df6e3b3ad9f9f --- /dev/null +++ b/src/language/ast/ASTSymbolTableBuilder.hpp @@ -0,0 +1,20 @@ +#ifndef AST_SYMBOL_TABLE_BUILDER_HPP +#define AST_SYMBOL_TABLE_BUILDER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/utils/SymbolTable.hpp> + +class ASTSymbolTableBuilder +{ + private: + void buildSymbolTable(ASTNode& node, std::shared_ptr<SymbolTable>& symbol_table); + + public: + ASTSymbolTableBuilder(ASTNode& root_node); + + ASTSymbolTableBuilder(const ASTSymbolTableBuilder&) = delete; + + ~ASTSymbolTableBuilder() = default; +}; + +#endif // AST_SYMBOL_TABLE_BUILDER_HPP diff --git a/src/language/ast/CMakeLists.txt b/src/language/ast/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4c31774302ccff20b3d24f686fd7e381ff43822 --- /dev/null +++ b/src/language/ast/CMakeLists.txt @@ -0,0 +1,30 @@ +# ------------------- Source files -------------------- + +add_library(PugsLanguageAST + ASTBuilder.cpp + ASTModulesImporter.cpp + ASTNodeAffectationExpressionBuilder.cpp + ASTNodeArraySubscriptExpressionBuilder.cpp + ASTNodeBinaryOperatorExpressionBuilder.cpp + ASTNodeBuiltinFunctionExpressionBuilder.cpp + ASTNodeDataTypeBuilder.cpp + ASTNodeDataTypeChecker.cpp + ASTNodeDataType.cpp + ASTNodeDataTypeFlattener.cpp + ASTNodeDeclarationToAffectationConverter.cpp + ASTNodeEmptyBlockCleaner.cpp + ASTNodeExpressionBuilder.cpp + ASTNodeFunctionEvaluationExpressionBuilder.cpp + ASTNodeFunctionExpressionBuilder.cpp + ASTNodeIncDecExpressionBuilder.cpp + ASTNodeJumpPlacementChecker.cpp + ASTNodeListAffectationExpressionBuilder.cpp + ASTNodeNaturalConversionChecker.cpp + ASTNodeUnaryOperatorExpressionBuilder.cpp + ASTSymbolInitializationChecker.cpp + ASTSymbolTableBuilder.cpp + ) + + +add_dependencies(PugsLanguageAST + PugsUtils) diff --git a/src/language/modules/BuiltinModule.cpp b/src/language/modules/BuiltinModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ab7911394a9ebb81454c3381a380ea4aca9c03e --- /dev/null +++ b/src/language/modules/BuiltinModule.cpp @@ -0,0 +1,29 @@ +#include <language/modules/BuiltinModule.hpp> + +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/TypeDescriptor.hpp> +#include <utils/Exceptions.hpp> + +#include <memory> + +void +BuiltinModule::_addBuiltinFunction(const std::string& name, + std::shared_ptr<IBuiltinFunctionEmbedder> builtin_function_embedder) +{ + auto [i_builtin_function, success] = + m_name_builtin_function_map.insert(std::make_pair(name, builtin_function_embedder)); + if (not success) { + throw NormalError("builtin-function '" + name + "' cannot be added!\n"); + } +} + +void +BuiltinModule::_addTypeDescriptor(const ASTNodeDataType& ast_node_data_type) +{ + Assert(ast_node_data_type == ASTNodeDataType::type_id_t); + std::shared_ptr type_descriptor = std::make_shared<TypeDescriptor>(ast_node_data_type.nameOfTypeId()); + auto [i_type, success] = m_name_type_map.insert(std::make_pair(type_descriptor->name(), type_descriptor)); + if (not success) { + throw NormalError("type '" + type_descriptor->name() + "' cannot be added!\n"); + } +} diff --git a/src/language/modules/BuiltinModule.hpp b/src/language/modules/BuiltinModule.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bf8743c9e5a9913dd6939e3d6cbe18495bccc27e --- /dev/null +++ b/src/language/modules/BuiltinModule.hpp @@ -0,0 +1,39 @@ +#ifndef BUILTIN_MODULE_HPP +#define BUILTIN_MODULE_HPP + +#include <language/ast/ASTNodeDataType.hpp> +#include <language/modules/IModule.hpp> + +class IBuiltinFunctionEmbedder; +class TypeDescriptor; + +class BuiltinModule : public IModule +{ + protected: + NameBuiltinFunctionMap m_name_builtin_function_map; + NameTypeMap m_name_type_map; + + void _addBuiltinFunction(const std::string& name, + std::shared_ptr<IBuiltinFunctionEmbedder> builtin_function_embedder); + + void _addTypeDescriptor(const ASTNodeDataType& type); + + public: + const NameBuiltinFunctionMap& + getNameBuiltinFunctionMap() const final + { + return m_name_builtin_function_map; + } + + const NameTypeMap& + getNameTypeMap() const final + { + return m_name_type_map; + } + + BuiltinModule() = default; + + ~BuiltinModule() = default; +}; + +#endif // BUILTIN_MODULE_HPP diff --git a/src/language/modules/CMakeLists.txt b/src/language/modules/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..703f19857cfb99c0053aecf1af0984dab371d72e --- /dev/null +++ b/src/language/modules/CMakeLists.txt @@ -0,0 +1,15 @@ +# ------------------- Source files -------------------- + +add_library(PugsLanguageModules + BuiltinModule.cpp + MathModule.cpp + MeshModule.cpp + ModuleRepository.cpp + SchemeModule.cpp + VTKModule.cpp +) + + +add_dependencies(PugsLanguageModules + PugsUtils + PugsMesh) diff --git a/src/language/modules/IModule.hpp b/src/language/modules/IModule.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b839ed496d8d032f660a6d21c484c7ca342c5f98 --- /dev/null +++ b/src/language/modules/IModule.hpp @@ -0,0 +1,31 @@ +#ifndef IMODULE_HPP +#define IMODULE_HPP + +#include <memory> +#include <string> +#include <string_view> +#include <unordered_map> + +class IBuiltinFunctionEmbedder; +class TypeDescriptor; + +class IModule +{ + public: + using NameBuiltinFunctionMap = std::unordered_map<std::string, std::shared_ptr<IBuiltinFunctionEmbedder>>; + using NameTypeMap = std::unordered_map<std::string, std::shared_ptr<TypeDescriptor>>; + + IModule() = default; + IModule(IModule&&) = default; + IModule& operator=(IModule&&) = default; + + virtual const NameBuiltinFunctionMap& getNameBuiltinFunctionMap() const = 0; + + virtual const NameTypeMap& getNameTypeMap() const = 0; + + virtual std::string_view name() const = 0; + + virtual ~IModule() = default; +}; + +#endif // IMODULE_HPP diff --git a/src/language/modules/MathModule.cpp b/src/language/modules/MathModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e774284b385e7e74b8cb715f73b5ebec6f81b02e --- /dev/null +++ b/src/language/modules/MathModule.cpp @@ -0,0 +1,72 @@ +#include <language/modules/MathModule.hpp> + +#include <language/utils/BuiltinFunctionEmbedder.hpp> + +MathModule::MathModule() +{ + this->_addBuiltinFunction("sqrt", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::sqrt(x); })); + + this->_addBuiltinFunction("abs", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::abs(x); })); + + this->_addBuiltinFunction("sin", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::sin(x); })); + + this->_addBuiltinFunction("cos", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::cos(x); })); + + this->_addBuiltinFunction("tan", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::tan(x); })); + + this->_addBuiltinFunction("asin", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::asin(x); })); + + this->_addBuiltinFunction("acos", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::acos(x); })); + + this->_addBuiltinFunction("atan", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::atan(x); })); + + this->_addBuiltinFunction("atan2", std::make_shared<BuiltinFunctionEmbedder<double(double, double)>>( + [](double x, double y) -> double { return std::atan2(x, y); })); + + this->_addBuiltinFunction("sinh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::sinh(x); })); + + this->_addBuiltinFunction("cosh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::cosh(x); })); + + this->_addBuiltinFunction("tanh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::tanh(x); })); + + this->_addBuiltinFunction("asinh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::asinh(x); })); + + this->_addBuiltinFunction("acosh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::acosh(x); })); + + this->_addBuiltinFunction("atanh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::atanh(x); })); + + this->_addBuiltinFunction("exp", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::exp(x); })); + + this->_addBuiltinFunction("log", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return std::log(x); })); + + this->_addBuiltinFunction("pow", std::make_shared<BuiltinFunctionEmbedder<double(double, double)>>( + [](double x, double y) -> double { return std::pow(x, y); })); + + this->_addBuiltinFunction("ceil", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>( + [](double x) -> int64_t { return std::ceil(x); })); + + this->_addBuiltinFunction("floor", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>( + [](double x) -> int64_t { return std::floor(x); })); + + this->_addBuiltinFunction("trunc", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>( + [](double x) -> int64_t { return std::trunc(x); })); + + this->_addBuiltinFunction("round", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>( + [](double x) -> int64_t { return std::lround(x); })); +} diff --git a/src/language/modules/MathModule.hpp b/src/language/modules/MathModule.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1f001e1938691c4227722adda9724c9d88f33137 --- /dev/null +++ b/src/language/modules/MathModule.hpp @@ -0,0 +1,20 @@ +#ifndef MATH_MODULE_HPP +#define MATH_MODULE_HPP + +#include <language/modules/BuiltinModule.hpp> + +class MathModule : public BuiltinModule +{ + public: + std::string_view + name() const final + { + return "math"; + } + + MathModule(); + + ~MathModule() = default; +}; + +#endif // MATH_MODULE_HPP diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9a65729637128081a7206ad6fa5d98ad95e9978 --- /dev/null +++ b/src/language/modules/MeshModule.cpp @@ -0,0 +1,193 @@ +#include <language/modules/MeshModule.hpp> + +#include <algebra/TinyVector.hpp> +#include <language/node_processor/ExecutionPolicy.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/FunctionTable.hpp> +#include <language/utils/PugsFunctionAdapter.hpp> +#include <language/utils/SymbolTable.hpp> +#include <language/utils/TypeDescriptor.hpp> +#include <mesh/CartesianMeshBuilder.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/DiamondDualMeshBuilder.hpp> +#include <mesh/GmshReader.hpp> +#include <mesh/Mesh.hpp> +#include <utils/Exceptions.hpp> + +#include <Kokkos_Core.hpp> + +template <typename T> +class MeshTransformation; +template <typename OutputType, typename InputType> +class MeshTransformation<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +{ + static constexpr size_t Dimension = OutputType::Dimension; + using Adapter = PugsFunctionAdapter<OutputType(InputType)>; + + public: + static inline std::shared_ptr<Mesh<Connectivity<Dimension>>> + transform(const FunctionSymbolId& function_symbol_id, std::shared_ptr<const IMesh> p_mesh) + { + using MeshType = Mesh<Connectivity<Dimension>>; + const MeshType& given_mesh = dynamic_cast<const MeshType&>(*p_mesh); + + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + + NodeValue<const InputType> given_xr = given_mesh.xr(); + NodeValue<OutputType> xr(given_mesh.connectivity()); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + parallel_for(given_mesh.numberOfNodes(), [=, &expression, &tokens](NodeId r) { + const int32_t t = tokens.acquire(); + + auto& execution_policy = context_list[t]; + + Adapter::convertArgs(execution_policy.currentContext(), given_xr[r]); + auto result = expression.execute(execution_policy); + xr[r] = convert_result(std::move(result)); + + tokens.release(t); + }); + + return std::make_shared<MeshType>(given_mesh.shared_connectivity(), xr); + } +}; + +MeshModule::MeshModule() +{ + this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IMesh>>); + + this->_addBuiltinFunction("readGmsh", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IMesh>(const std::string&)>>( + + [](const std::string& file_name) -> std::shared_ptr<const IMesh> { + GmshReader gmsh_reader(file_name); + return gmsh_reader.mesh(); + } + + )); + + this->_addBuiltinFunction("transform", + std::make_shared<BuiltinFunctionEmbedder< + std::shared_ptr<const IMesh>(std::shared_ptr<const IMesh>, const FunctionSymbolId&)>>( + + [](std::shared_ptr<const IMesh> p_mesh, + const FunctionSymbolId& function_id) -> std::shared_ptr<const IMesh> { + switch (p_mesh->dimension()) { + case 1: { + using TransformT = TinyVector<1>(TinyVector<1>); + return MeshTransformation<TransformT>::transform(function_id, p_mesh); + } + case 2: { + using TransformT = TinyVector<2>(TinyVector<2>); + return MeshTransformation<TransformT>::transform(function_id, p_mesh); + } + case 3: { + using TransformT = TinyVector<3>(TinyVector<3>); + return MeshTransformation<TransformT>::transform(function_id, p_mesh); + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } + } + + )); + + this->_addBuiltinFunction("cartesian1dMesh", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< + const IMesh>(const TinyVector<1>, const TinyVector<1>, const std::vector<uint64_t>&)>>( + + [](const TinyVector<1> a, const TinyVector<1> b, + const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const IMesh> { + constexpr uint64_t dimension = 1; + + if (box_sizes.size() != dimension) { + throw NormalError("expecting " + std::to_string(dimension) + + " dimensions, provided " + std::to_string(box_sizes.size())); + } + + const TinyVector<dimension, uint64_t> sizes = [&]() { + TinyVector<dimension, uint64_t> s; + for (size_t i = 0; i < dimension; ++i) { + s[i] = box_sizes[i]; + } + return s; + }(); + + CartesianMeshBuilder builder{a, b, sizes}; + return builder.mesh(); + } + + )); + + this->_addBuiltinFunction("cartesian2dMesh", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< + const IMesh>(const TinyVector<2>, const TinyVector<2>, const std::vector<uint64_t>&)>>( + + [](const TinyVector<2> a, const TinyVector<2> b, + const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const IMesh> { + constexpr uint64_t dimension = 2; + + if (box_sizes.size() != dimension) { + throw NormalError("expecting " + std::to_string(dimension) + + " dimensions, provided " + std::to_string(box_sizes.size())); + } + + const TinyVector<dimension, uint64_t> sizes = [&]() { + TinyVector<dimension, uint64_t> s; + for (size_t i = 0; i < dimension; ++i) { + s[i] = box_sizes[i]; + } + return s; + }(); + + CartesianMeshBuilder builder{a, b, sizes}; + return builder.mesh(); + } + + )); + + this->_addBuiltinFunction("cartesian3dMesh", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< + const IMesh>(const TinyVector<3>&, const TinyVector<3>&, const std::vector<uint64_t>&)>>( + + [](const TinyVector<3>& a, const TinyVector<3>& b, + const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const IMesh> { + constexpr uint64_t dimension = 3; + + if (box_sizes.size() != dimension) { + throw NormalError("expecting " + std::to_string(dimension) + + " dimensions, provided " + std::to_string(box_sizes.size())); + } + + const TinyVector<dimension, uint64_t> sizes = [&]() { + TinyVector<dimension, uint64_t> s; + for (size_t i = 0; i < dimension; ++i) { + s[i] = box_sizes[i]; + } + return s; + }(); + + CartesianMeshBuilder builder{a, b, sizes}; + return builder.mesh(); + } + + )); + + this->_addBuiltinFunction("diamondDual", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IMesh>( + const std::shared_ptr<const IMesh>&)>>( + + [](const std::shared_ptr<const IMesh>& p_mesh) -> std::shared_ptr<const IMesh> { + DiamondDualMeshBuilder builder{p_mesh}; + return builder.mesh(); + } + + )); +} diff --git a/src/language/modules/MeshModule.hpp b/src/language/modules/MeshModule.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f2c3d3d6360e5fd378d128d3b6b57e0de5a04509 --- /dev/null +++ b/src/language/modules/MeshModule.hpp @@ -0,0 +1,27 @@ +#ifndef MESH_MODULE_HPP +#define MESH_MODULE_HPP + +#include <language/modules/BuiltinModule.hpp> +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <utils/PugsMacros.hpp> + +class IMesh; + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IMesh>> = {ASTNodeDataType::type_id_t, "mesh"}; + +class MeshModule : public BuiltinModule +{ + public: + std::string_view + name() const final + { + return "mesh"; + } + + MeshModule(); + + ~MeshModule() = default; +}; + +#endif // MESH_MODULE_HPP diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp new file mode 100644 index 0000000000000000000000000000000000000000..768661e9999a3dd720455f23daa7c252f555d16f --- /dev/null +++ b/src/language/modules/ModuleRepository.cpp @@ -0,0 +1,73 @@ +#include <language/modules/ModuleRepository.hpp> + +#include <language/ast/ASTNode.hpp> +#include <language/modules/MathModule.hpp> +#include <language/modules/MeshModule.hpp> +#include <language/modules/SchemeModule.hpp> +#include <language/modules/VTKModule.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/PugsAssert.hpp> + +void +ModuleRepository::_subscribe(std::unique_ptr<IModule> m) +{ + auto [i_module, success] = m_module_set.emplace(m->name(), std::move(m)); + Assert(success, "module has already been subscribed"); +} + +ModuleRepository::ModuleRepository() +{ + this->_subscribe(std::make_unique<MathModule>()); + this->_subscribe(std::make_unique<MeshModule>()); + this->_subscribe(std::make_unique<VTKModule>()); + this->_subscribe(std::make_unique<SchemeModule>()); +} + +template <typename NameEmbedderMapT, typename EmbedderTableT> +void +ModuleRepository::_populateEmbedderTableT(const ASTNode& module_name_node, + const NameEmbedderMapT& name_embedder_map, + const ASTNodeDataType& data_type, + SymbolTable& symbol_table, + EmbedderTableT& embedder_table) +{ + const std::string& module_name = module_name_node.string(); + + for (auto [symbol_name, embedded] : name_embedder_map) { + auto [i_symbol, success] = symbol_table.add(symbol_name, module_name_node.begin()); + + if (not success) { + std::ostringstream error_message; + error_message << "importing module '" << module_name << "', cannot add symbol '" << symbol_name + << "', it is already defined!"; + throw parse_error(error_message.str(), module_name_node.begin()); + } + + i_symbol->attributes().setDataType(data_type); + i_symbol->attributes().setIsInitialized(); + i_symbol->attributes().value() = embedder_table.size(); + + embedder_table.add(embedded); + } +} + +void +ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table) +{ + const std::string& module_name = module_name_node.string(); + + auto i_module = m_module_set.find(module_name); + if (i_module != m_module_set.end()) { + const IModule& populating_module = *i_module->second; + + this->_populateEmbedderTableT(module_name_node, populating_module.getNameBuiltinFunctionMap(), + ASTNodeDataType::builtin_function_t, symbol_table, + symbol_table.builtinFunctionEmbedderTable()); + + this->_populateEmbedderTableT(module_name_node, populating_module.getNameTypeMap(), ASTNodeDataType::type_name_id_t, + symbol_table, symbol_table.typeEmbedderTable()); + } else { + throw parse_error(std::string{"could not find module "} + module_name, std::vector{module_name_node.begin()}); + } +} diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f928a1552563612ed77434e4295a2d31fb2969c1 --- /dev/null +++ b/src/language/modules/ModuleRepository.hpp @@ -0,0 +1,41 @@ +#ifndef MODULE_REGISTRY_HPP +#define MODULE_REGISTRY_HPP + +#include <language/modules/IModule.hpp> + +#include <map> +#include <memory> +#include <string> + +class ASTNode; +class ASTNodeDataType; +class SymbolTable; + +class ModuleRepository +{ + private: + std::map<std::string, std::unique_ptr<IModule>> m_module_set; + + void _subscribe(std::unique_ptr<IModule> a); + + template <typename NameEmbedderMapT, typename EmbedderTableT> + void _populateEmbedderTableT(const ASTNode& module_name_node, + const NameEmbedderMapT& name_embedder_map, + const ASTNodeDataType& data_type, + SymbolTable& symbol_table, + EmbedderTableT& embedder_table); + + public: + void populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table); + + const ModuleRepository& operator=(const ModuleRepository&) = delete; + const ModuleRepository& operator=(ModuleRepository&&) = delete; + + ModuleRepository(const ModuleRepository&) = delete; + ModuleRepository(ModuleRepository&&) = delete; + + ModuleRepository(); + ~ModuleRepository() = default; +}; + +#endif // MODULE_REGISTRY_HPP diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1d6068829fb5df8bfa681976a75605ce8a6f469 --- /dev/null +++ b/src/language/modules/SchemeModule.cpp @@ -0,0 +1,270 @@ +#include <language/modules/SchemeModule.hpp> + +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/TypeDescriptor.hpp> +#include <mesh/Mesh.hpp> +#include <scheme/AcousticSolver.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> +#include <scheme/NamedBoundaryDescriptor.hpp> +#include <scheme/NumberedBoundaryDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> + +#include <memory> + +/////////// TEMPORARY + +#include <language/utils/PugsFunctionAdapter.hpp> +#include <output/VTKWriter.hpp> + +template <typename T> +class InterpolateItemValue; +template <typename OutputType, typename InputType> +class InterpolateItemValue<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +{ + static constexpr size_t Dimension = OutputType::Dimension; + using Adapter = PugsFunctionAdapter<OutputType(InputType)>; + + public: + template <ItemType item_type> + static inline ItemValue<OutputType, item_type> + interpolate(const FunctionSymbolId& function_symbol_id, const ItemValue<const InputType, item_type>& position) + { + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + const IConnectivity& connectivity = *position.connectivity_ptr(); + + ItemValue<OutputType, item_type> value(connectivity); + using ItemId = ItemIdT<item_type>; + + parallel_for(connectivity.template numberOf<item_type>(), [=, &expression, &tokens](ItemId i) { + const int32_t t = tokens.acquire(); + + auto& execution_policy = context_list[t]; + + Adapter::convertArgs(execution_policy.currentContext(), position[i]); + auto result = expression.execute(execution_policy); + value[i] = convert_result(std::move(result)); + + tokens.release(t); + }); + + return value; + } +}; + +template <size_t Dimension> +struct GlaceScheme +{ + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + using MeshDataType = MeshData<Dimension>; + using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; + + std::shared_ptr<const MeshType> m_mesh; + + GlaceScheme(std::shared_ptr<const IMesh> i_mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const FunctionSymbolId& rho_id, + const FunctionSymbolId& u_id, + const FunctionSymbolId& p_id) + : m_mesh{std::dynamic_pointer_cast<const MeshType>(i_mesh)} + { + MeshDataType mesh_data(*m_mesh); + + std::cout << "number of bc descr = " << bc_descriptor_list.size() << '\n'; + + std::vector<BoundaryConditionHandler> bc_list; + { + constexpr ItemType FaceType = [] { + if constexpr (Dimension > 1) { + return ItemType::face; + } else { + return ItemType::node; + } + }(); + + for (const auto& bc_descriptor : bc_descriptor_list) { + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = + dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); + for (size_t i_ref_face_list = 0; + i_ref_face_list < m_mesh->connectivity().template numberOfRefItemList<FaceType>(); ++i_ref_face_list) { + const auto& ref_face_list = m_mesh->connectivity().template refItemList<FaceType>(i_ref_face_list); + const RefId& ref = ref_face_list.refId(); + if (ref == sym_bc_descriptor.boundaryDescriptor()) { + SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = + new SymmetryBoundaryCondition<MeshType::Dimension>( + MeshFlatNodeBoundary<MeshType::Dimension>(m_mesh, ref_face_list)); + std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); + bc_list.push_back(BoundaryConditionHandler(bc)); + } + } + break; + } + default: { + throw UnexpectedError("Unknown BCDescription\n"); + } + } + } + } + + UnknownsType unknowns(mesh_data); + + unknowns.rhoj() = + InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(rho_id, mesh_data.xj()); + + unknowns.pj() = + InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(p_id, mesh_data.xj()); + + unknowns.uj() = + InterpolateItemValue<TinyVector<Dimension>(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(u_id, + mesh_data + .xj()); + unknowns.gammaj().fill(1.4); + + AcousticSolver acoustic_solver(m_mesh, bc_list); + + const CellValue<const double>& Vj = mesh_data.Vj(); + + const double tmax = 0.2; + double t = 0; + + int itermax = std::numeric_limits<int>::max(); + int iteration = 0; + + CellValue<double>& rhoj = unknowns.rhoj(); + CellValue<double>& ej = unknowns.ej(); + CellValue<double>& pj = unknowns.pj(); + CellValue<double>& gammaj = unknowns.gammaj(); + CellValue<double>& cj = unknowns.cj(); + CellValue<TinyVector<Dimension>>& uj = unknowns.uj(); + CellValue<double>& Ej = unknowns.Ej(); + CellValue<double>& mj = unknowns.mj(); + CellValue<double>& inv_mj = unknowns.invMj(); + + BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); + block_eos.updateEandCFromRhoP(); + + parallel_for( + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { Ej[j] = ej[j] + 0.5 * (uj[j], uj[j]); }); + + parallel_for( + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { mj[j] = rhoj[j] * Vj[j]; }); + + parallel_for( + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { inv_mj[j] = 1. / mj[j]; }); + + VTKWriter vtk_writer("mesh_" + std::to_string(Dimension), 0.01); + + while ((t < tmax) and (iteration < itermax)) { + vtk_writer.write(m_mesh, + {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, + NamedItemValue{"coords", m_mesh->xr()}, + NamedItemValue{"cell_owner", m_mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", m_mesh->connectivity().nodeOwner()}}, + t); + double dt = 0.4 * acoustic_solver.acoustic_dt(Vj, cj); + if (t + dt > tmax) { + dt = tmax - t; + } + + std::cout.setf(std::cout.scientific); + std::cout << "iteration " << rang::fg::cyan << std::setw(4) << iteration << rang::style::reset + << " time=" << rang::fg::green << t << rang::style::reset << " dt=" << rang::fgB::blue << dt + << rang::style::reset << '\n'; + + m_mesh = acoustic_solver.computeNextStep(dt, unknowns); + + block_eos.updatePandCFromRhoE(); + + t += dt; + ++iteration; + } + std::cout << rang::style::bold << "Final time=" << rang::fgB::green << t << rang::style::reset << " reached after " + << rang::fgB::cyan << iteration << rang::style::reset << rang::style::bold << " iterations" + << rang::style::reset << '\n'; + vtk_writer.write(m_mesh, + {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, + NamedItemValue{"coords", m_mesh->xr()}, + NamedItemValue{"cell_owner", m_mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", m_mesh->connectivity().nodeOwner()}}, + t, true); // forces last output + } +}; + +SchemeModule::SchemeModule() +{ + this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IBoundaryDescriptor>>); + this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IBoundaryConditionDescriptor>>); + + this->_addBuiltinFunction("boundaryName", + std::make_shared< + BuiltinFunctionEmbedder<std::shared_ptr<const IBoundaryDescriptor>(const std::string&)>>( + + [](const std::string& boundary_name) -> std::shared_ptr<const IBoundaryDescriptor> { + return std::make_shared<NamedBoundaryDescriptor>(boundary_name); + } + + )); + + this->_addBuiltinFunction("boundaryTag", + std::make_shared< + BuiltinFunctionEmbedder<std::shared_ptr<const IBoundaryDescriptor>(int64_t)>>( + + [](int64_t boundary_tag) -> std::shared_ptr<const IBoundaryDescriptor> { + return std::make_shared<NumberedBoundaryDescriptor>(boundary_tag); + } + + )); + + this + ->_addBuiltinFunction("symmetry", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IBoundaryConditionDescriptor>( + std::shared_ptr<const IBoundaryDescriptor>)>>( + + [](std::shared_ptr<const IBoundaryDescriptor> boundary) + -> std::shared_ptr<const IBoundaryConditionDescriptor> { + return std::make_shared<SymmetryBoundaryConditionDescriptor>(boundary); + } + + )); + + this->_addBuiltinFunction("glace", + std::make_shared<BuiltinFunctionEmbedder< + void(std::shared_ptr<const IMesh>, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&, + const FunctionSymbolId&, const FunctionSymbolId&, const FunctionSymbolId&)>>( + + [](std::shared_ptr<const IMesh> p_mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list, + const FunctionSymbolId& rho_id, const FunctionSymbolId& u_id, + const FunctionSymbolId& p_id) -> void { + switch (p_mesh->dimension()) { + case 1: { + GlaceScheme<1>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id}; + break; + } + case 2: { + GlaceScheme<2>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id}; + break; + } + case 3: { + GlaceScheme<3>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id}; + break; + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } + } + + )); +} diff --git a/src/language/modules/SchemeModule.hpp b/src/language/modules/SchemeModule.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3c70be9a2db29d634b71ea96fb60fce38183c85d --- /dev/null +++ b/src/language/modules/SchemeModule.hpp @@ -0,0 +1,32 @@ +#ifndef SCHEME_MODULE_HPP +#define SCHEME_MODULE_HPP + +#include <language/modules/BuiltinModule.hpp> +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <utils/PugsMacros.hpp> + +class IBoundaryDescriptor; +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IBoundaryDescriptor>> = + {ASTNodeDataType::type_id_t, "boundary"}; + +class IBoundaryConditionDescriptor; +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IBoundaryConditionDescriptor>> = + {ASTNodeDataType::type_id_t, "boundary_condition"}; + +class SchemeModule : public BuiltinModule +{ + public: + std::string_view + name() const final + { + return "scheme"; + } + + SchemeModule(); + + ~SchemeModule() = default; +}; + +#endif // SCHEME_MODULE_HPP diff --git a/src/language/modules/VTKModule.cpp b/src/language/modules/VTKModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f815a78e763b387ee5707d9ac65ec1f038a36b14 --- /dev/null +++ b/src/language/modules/VTKModule.cpp @@ -0,0 +1,52 @@ +#include <language/modules/VTKModule.hpp> + +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/TypeDescriptor.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/GmshReader.hpp> +#include <mesh/Mesh.hpp> +#include <output/VTKWriter.hpp> + +VTKModule::VTKModule() +{ + this->_addBuiltinFunction("writeVTK", + std::make_shared< + BuiltinFunctionEmbedder<void(std::shared_ptr<const IMesh>, const std::string&)>>( + + [](std::shared_ptr<const IMesh> p_mesh, const std::string& filename) -> void { + VTKWriter writer(filename, 0.1); + + static double time = 0; + + switch (p_mesh->dimension()) { + case 1: { + using MeshType = Mesh<Connectivity<1>>; + const std::shared_ptr<const MeshType> mesh = + std::dynamic_pointer_cast<const MeshType>(p_mesh); + + writer.write(mesh, OutputNamedItemValueSet{}, time, true); + break; + } + case 2: { + using MeshType = Mesh<Connectivity<2>>; + const std::shared_ptr<const MeshType> mesh = + std::dynamic_pointer_cast<const MeshType>(p_mesh); + + writer.write(mesh, OutputNamedItemValueSet{}, time, true); + break; + } + case 3: { + using MeshType = Mesh<Connectivity<3>>; + const std::shared_ptr<const MeshType> mesh = + std::dynamic_pointer_cast<const MeshType>(p_mesh); + + writer.write(mesh, OutputNamedItemValueSet{}, time, true); + break; + } + } + + time++; + } + + )); +} diff --git a/src/language/modules/VTKModule.hpp b/src/language/modules/VTKModule.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1578fad811b7dae1181053317e891dbb865ad035 --- /dev/null +++ b/src/language/modules/VTKModule.hpp @@ -0,0 +1,21 @@ +#ifndef VTK_MODULE_HPP +#define VTK_MODULE_HPP + +#include <language/modules/BuiltinModule.hpp> +#include <utils/PugsMacros.hpp> + +class VTKModule : public BuiltinModule +{ + public: + std::string_view + name() const final + { + return "vtk"; + } + + VTKModule(); + + ~VTKModule() = default; +}; + +#endif // VTK_MODULE_HPP diff --git a/src/language/node_processor/ASTNodeExpressionListProcessor.hpp b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ec37d74ee5c815695c229d3b93d5d0acdb79bc9d --- /dev/null +++ b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp @@ -0,0 +1,95 @@ +#ifndef AST_NODE_EXPRESSION_LIST_PROCESSOR_HPP +#define AST_NODE_EXPRESSION_LIST_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> + +#include <vector> + +class ASTNodeExpressionListProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + const size_t m_number_of_values; + + void + _flattenResults(DataVariant&& value, std::vector<DataVariant>& list_values) + { + std::visit( + [&](auto&& v) { + using ValueT = std::decay_t<decltype(v)>; + if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) { + if (v.isFlattenable()) { + for (size_t i = 0; i < v.size(); ++i) { + _flattenResults(std::move(v[i]), list_values); + } + } else { + list_values.emplace_back(v); + } + } else { + list_values.emplace_back(v); + } + }, + value); + } + + size_t + _getNumberOfValues() const + { + size_t number_of_values = 0; + + for (auto& child : m_node.children) { + if (child->is_type<language::function_evaluation>()) { + if (child->m_data_type != ASTNodeDataType::typename_t) { + ++number_of_values; + } else { + ASTNode& function_name_node = *child->children[0]; + + auto [i_function_symbol, found] = m_node.m_symbol_table->find(function_name_node.string(), m_node.begin()); + Assert(found); + + switch (i_function_symbol->attributes().dataType()) { + case ASTNodeDataType::function_t: { + uint64_t function_id = std::get<uint64_t>(i_function_symbol->attributes().value()); + + FunctionDescriptor& function_descriptor = m_node.m_symbol_table->functionTable()[function_id]; + + ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1]; + number_of_values += function_image_domain.children.size(); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected function type", m_node.begin()); + } + // LCOV_EXCL_STOP + } + } + } else { + ++number_of_values; + } + } + + return number_of_values; + } + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + std::vector<DataVariant> list_values; + list_values.reserve(m_number_of_values); + + for (auto& child : m_node.children) { + _flattenResults(child->execute(exec_policy), list_values); + } + + Assert(list_values.size() == m_number_of_values); + return DataVariant{std::move(list_values)}; + } + + ASTNodeExpressionListProcessor(ASTNode& node) : m_node{node}, m_number_of_values{this->_getNumberOfValues()} {} +}; + +#endif // AST_NODE_EXPRESSION_LIST_PROCESSOR_HPP diff --git a/src/language/node_processor/ASTNodeListProcessor.hpp b/src/language/node_processor/ASTNodeListProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..df29d82de3cf317aa02ddb3f49838ec0a0325c0e --- /dev/null +++ b/src/language/node_processor/ASTNodeListProcessor.hpp @@ -0,0 +1,29 @@ +#ifndef AST_NODE_LIST_PROCESSOR_HPP +#define AST_NODE_LIST_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class ASTNodeListProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + for (auto& child : m_node.children) { + child->execute(exec_policy); + } + + if (not(m_node.is_root() or m_node.is_type<language::for_statement_block>())) + m_node.m_symbol_table->clearValues(); + + return {}; + } + + ASTNodeListProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // AST_NODE_LIST_PROCESSOR_HPP diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..31e1f070f5fadc1366ad4470b49a8052977bfce2 --- /dev/null +++ b/src/language/node_processor/AffectationProcessor.hpp @@ -0,0 +1,716 @@ +#ifndef AFFECTATION_PROCESSOR_HPP +#define AFFECTATION_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/Exceptions.hpp> +#include <utils/PugsTraits.hpp> + +template <typename Op> +struct AffOp; + +template <> +struct AffOp<language::multiplyeq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a *= b; + } +}; + +template <> +struct AffOp<language::divideeq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a /= b; + } +}; + +template <> +struct AffOp<language::pluseq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a += b; + } +}; + +template <> +struct AffOp<language::minuseq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a -= b; + } +}; + +struct IAffectationExecutor +{ + virtual void affect(ExecutionPolicy& exec_policy, DataVariant&& rhs) = 0; + + IAffectationExecutor(const IAffectationExecutor&) = delete; + IAffectationExecutor(IAffectationExecutor&&) = delete; + + IAffectationExecutor() = default; + + virtual ~IAffectationExecutor() = default; +}; + +template <typename OperatorT, typename ValueT, typename DataT> +class AffectationExecutor final : public IAffectationExecutor +{ + private: + ValueT& m_lhs; + + static inline const bool m_is_defined{[] { + if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) { + if constexpr (not std::is_same_v<OperatorT, language::eq_op>) { + return false; + } + } + return true; + }()}; + + public: + AffectationExecutor(ASTNode& node, ValueT& lhs) : m_lhs(lhs) + { + // LCOV_EXCL_START + if constexpr (not m_is_defined) { + throw parse_error("unexpected error: invalid operands to affectation expression", std::vector{node.begin()}); + } + // LCOV_EXCL_STOP + } + + PUGS_INLINE void + affect(ExecutionPolicy&, DataVariant&& rhs) + { + if constexpr (m_is_defined) { + if constexpr (not std::is_same_v<DataT, ZeroType>) { + if constexpr (std::is_same_v<ValueT, std::string>) { + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + if constexpr (std::is_same_v<std::string, DataT>) { + m_lhs = std::get<DataT>(rhs); + } else if constexpr (std::is_arithmetic_v<DataT>) { + m_lhs = std::to_string(std::get<DataT>(rhs)); + } else { + std::ostringstream os; + os << std::get<DataT>(rhs) << std::ends; + m_lhs = os.str(); + } + } else { + if constexpr (std::is_same_v<std::string, DataT>) { + m_lhs += std::get<std::string>(rhs); + } else if constexpr (std::is_arithmetic_v<DataT>) { + m_lhs += std::to_string(std::get<DataT>(rhs)); + } else { + std::ostringstream os; + os << std::get<DataT>(rhs) << std::ends; + m_lhs += os.str(); + } + } + } else { + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + if constexpr (std::is_convertible_v<ValueT, DataT>) { + m_lhs = std::get<DataT>(rhs); + } else if constexpr (std::is_same_v<DataT, AggregateDataVariant>) { + const AggregateDataVariant& v = std::get<AggregateDataVariant>(rhs); + static_assert(is_tiny_vector_v<ValueT>, "expecting lhs TinyVector"); + for (size_t i = 0; i < m_lhs.dimension(); ++i) { + std::visit( + [&](auto&& vi) { + using Vi_T = std::decay_t<decltype(vi)>; + if constexpr (std::is_convertible_v<Vi_T, double>) { + m_lhs[i] = vi; + } else { + throw UnexpectedError("unexpected rhs type in affectation"); + } + }, + v[i]); + } + } else if constexpr (std::is_same_v<TinyVector<1>, ValueT>) { + std::visit( + [&](auto&& v) { + using Vi_T = std::decay_t<decltype(v)>; + if constexpr (std::is_convertible_v<Vi_T, double>) { + m_lhs = v; + } else { + throw UnexpectedError("unexpected rhs type in affectation"); + } + }, + rhs); + } + } else { + AffOp<OperatorT>().eval(m_lhs, std::get<DataT>(rhs)); + } + } + } else if (std::is_same_v<OperatorT, language::eq_op>) { + m_lhs = ValueT{zero}; + } else { + static_assert(std::is_same_v<OperatorT, language::eq_op>, "unexpected operator type"); + } + } + } +}; + +template <typename OperatorT, typename ArrayT, typename ValueT, typename DataT> +class ComponentAffectationExecutor final : public IAffectationExecutor +{ + private: + ArrayT& m_lhs_array; + ASTNode& m_index_expression; + + static inline const bool m_is_defined{[] { + if constexpr (not std::is_same_v<typename ArrayT::data_type, ValueT>) { + return false; + } else if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) { + if constexpr (not std::is_same_v<OperatorT, language::eq_op>) { + return false; + } + } + return true; + }()}; + + public: + ComponentAffectationExecutor(ASTNode& node, ArrayT& lhs_array, ASTNode& index_expression) + : m_lhs_array{lhs_array}, m_index_expression{index_expression} + { + // LCOV_EXCL_START + if constexpr (not m_is_defined) { + throw parse_error("unexpected error: invalid operands to affectation expression", std::vector{node.begin()}); + } + // LCOV_EXCL_STOP + } + + PUGS_INLINE void + affect(ExecutionPolicy& exec_policy, DataVariant&& rhs) + { + if constexpr (m_is_defined) { + const int64_t index_value = [&](DataVariant&& value_variant) -> int64_t { + int64_t index_value = 0; + std::visit( + [&](auto&& value) { + using IndexValueT = std::decay_t<decltype(value)>; + if constexpr (std::is_integral_v<IndexValueT>) { + index_value = value; + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid index type", std::vector{m_index_expression.begin()}); + // LCOV_EXCL_STOP + } + }, + value_variant); + return index_value; + }(m_index_expression.execute(exec_policy)); + + if constexpr (std::is_same_v<ValueT, std::string>) { + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + if constexpr (std::is_same_v<std::string, DataT>) { + m_lhs_array[index_value] = std::get<DataT>(rhs); + } else { + m_lhs_array[index_value] = std::to_string(std::get<DataT>(rhs)); + } + } else { + if constexpr (std::is_same_v<std::string, DataT>) { + m_lhs_array[index_value] += std::get<std::string>(rhs); + } else { + m_lhs_array[index_value] += std::to_string(std::get<DataT>(rhs)); + } + } + } else { + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + if constexpr (std::is_same_v<ValueT, DataT>) { + m_lhs_array[index_value] = std::get<DataT>(rhs); + } else { + m_lhs_array[index_value] = static_cast<ValueT>(std::get<DataT>(rhs)); + } + } else { + AffOp<OperatorT>().eval(m_lhs_array[index_value], std::get<DataT>(rhs)); + } + } + } + } +}; + +template <typename OperatorT, typename ValueT, typename DataT> +class AffectationProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + std::unique_ptr<IAffectationExecutor> m_affectation_executor; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + m_affectation_executor->affect(exec_policy, m_node.children[1]->execute(exec_policy)); + + return {}; + } + + AffectationProcessor(ASTNode& node) : m_node{node} + { + if (node.children[0]->is_type<language::name>()) { + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin()); + Assert(found); + DataVariant& value = i_symbol->attributes().value(); + + if (not std::holds_alternative<ValueT>(value)) { + value = ValueT{}; + } + + using AffectationExecutorT = AffectationExecutor<OperatorT, ValueT, DataT>; + m_affectation_executor = std::make_unique<AffectationExecutorT>(m_node, std::get<ValueT>(value)); + } else if (node.children[0]->is_type<language::subscript_expression>()) { + auto& array_subscript_expression = *node.children[0]; + + auto& array_expression = *array_subscript_expression.children[0]; + Assert(array_expression.is_type<language::name>()); + + const std::string& symbol = array_expression.string(); + + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, array_subscript_expression.begin()); + Assert(found); + DataVariant& value = i_symbol->attributes().value(); + + // LCOV_EXCL_START + if (array_expression.m_data_type != ASTNodeDataType::vector_t) { + throw parse_error("unexpected error: invalid lhs (expecting R^d)", + std::vector{array_subscript_expression.begin()}); + } + // LCOV_EXCL_STOP + + auto& index_expression = *array_subscript_expression.children[1]; + + switch (array_expression.m_data_type.dimension()) { + case 1: { + using ArrayTypeT = TinyVector<1>; + if (not std::holds_alternative<ArrayTypeT>(value)) { + value = ArrayTypeT{}; + } + using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>; + m_affectation_executor = + std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value), index_expression); + break; + } + case 2: { + using ArrayTypeT = TinyVector<2>; + if (not std::holds_alternative<ArrayTypeT>(value)) { + value = ArrayTypeT{}; + } + using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>; + m_affectation_executor = + std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value), index_expression); + break; + } + case 3: { + using ArrayTypeT = TinyVector<3>; + if (not std::holds_alternative<ArrayTypeT>(value)) { + value = ArrayTypeT{}; + } + using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>; + m_affectation_executor = + std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value), index_expression); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector dimension", + std::vector{array_subscript_expression.begin()}); + } + // LCOV_EXCL_STOP + } + + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid lhs", std::vector{node.children[0]->begin()}); + // LCOV_EXCL_STOP + } + } +}; + +template <typename OperatorT, typename ValueT> +class AffectationToTinyVectorFromListProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + DataVariant* m_lhs; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy)); + + static_assert(std::is_same_v<OperatorT, language::eq_op>, "forbidden affection operator for list to vectors"); + + ValueT v; + for (size_t i = 0; i < v.dimension(); ++i) { + std::visit( + [&](auto&& child_value) { + using T = std::decay_t<decltype(child_value)>; + if constexpr (std::is_same_v<T, bool> or std::is_same_v<T, uint64_t> or std::is_same_v<T, int64_t> or + std::is_same_v<T, double>) { + v[i] = child_value; + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: unexpected right hand side type in affectation", m_node.begin()); + // LCOV_EXCL_STOP + } + }, + children_values[i]); + } + + *m_lhs = v; + return {}; + } + + AffectationToTinyVectorFromListProcessor(ASTNode& node) : m_node{node} + { + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin()); + Assert(found); + + m_lhs = &i_symbol->attributes().value(); + } +}; + +template <typename OperatorT, typename ValueT> +class AffectationToTupleProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + DataVariant* m_lhs; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + static_assert(std::is_same_v<OperatorT, language::eq_op>, "forbidden affection operator to tuples"); + DataVariant value = m_node.children[1]->execute(exec_policy); + + std::visit( + [&](auto&& v) { + using T = std::decay_t<decltype(v)>; + if constexpr (std::is_same_v<T, ValueT>) { + *m_lhs = std::vector{std::move(v)}; + } else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<T, ValueT>) { + *m_lhs = std::vector{std::move(static_cast<ValueT>(v))}; + } else if constexpr (std::is_same_v<std::string, ValueT>) { + if constexpr (std::is_arithmetic_v<T>) { + *m_lhs = std::vector{std::move(std::to_string(v))}; + } else { + std::ostringstream os; + os << v << std::ends; + *m_lhs = std::vector{os.str()}; + } + } else if constexpr (std::is_same_v<ValueT, TinyVector<1>> and std::is_arithmetic_v<T>) { + *m_lhs = std::vector{TinyVector<1>{static_cast<double>(v)}}; + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: unexpected right hand side type in affectation", m_node.begin()); + // LCOV_EXCL_STOP + } + }, + value); + + return {}; + } + + AffectationToTupleProcessor(ASTNode& node) : m_node{node} + { + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin()); + Assert(found); + + m_lhs = &i_symbol->attributes().value(); + } +}; + +template <typename OperatorT, typename ValueT> +class AffectationToTupleFromListProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + DataVariant* m_lhs; + + void + _copyAggregateDataVariant(const AggregateDataVariant& children_values) + { + std::vector<ValueT> tuple_value(children_values.size()); + for (size_t i = 0; i < children_values.size(); ++i) { + std::visit( + [&](auto&& child_value) { + using T = std::decay_t<decltype(child_value)>; + if constexpr (std::is_same_v<T, ValueT>) { + tuple_value[i] = child_value; + } else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<T, ValueT>) { + tuple_value[i] = static_cast<ValueT>(child_value); + } else if constexpr (std::is_same_v<std::string, ValueT>) { + if constexpr (std::is_arithmetic_v<T>) { + tuple_value[i] = std::to_string(child_value); + } else { + std::ostringstream os; + os << child_value << std::ends; + tuple_value[i] = os.str(); + } + } else if constexpr (is_tiny_vector_v<ValueT>) { + if constexpr (std::is_same_v<T, AggregateDataVariant>) { + ValueT& v = tuple_value[i]; + Assert(ValueT::Dimension == child_value.size()); + for (size_t j = 0; j < ValueT::Dimension; ++j) { + std::visit( + [&](auto&& vj) { + using Ti = std::decay_t<decltype(vj)>; + if constexpr (std::is_convertible_v<Ti, typename ValueT::data_type>) { + v[j] = vj; + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: unexpected right hand side type in affectation", + m_node.children[1]->children[i]->begin()); + // LCOV_EXCL_STOP + } + }, + child_value[j]); + } + } else if constexpr (std::is_same_v<T, int64_t>) { + // in this case a 0 is given + Assert(child_value == 0); + tuple_value[i] = ZeroType{}; + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: unexpected right hand side type in affectation", + m_node.children[1]->children[i]->begin()); + // LCOV_EXCL_STOP + } + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: unexpected right hand side type in affectation", + m_node.children[1]->children[i]->begin()); + // LCOV_EXCL_STOP + } + }, + children_values[i]); + } + *m_lhs = std::move(tuple_value); + } + + template <typename DataType> + void + _copyVector(const std::vector<DataType>& values) + { + std::vector<ValueT> v(values.size()); + if constexpr (std::is_same_v<ValueT, DataType>) { + for (size_t i = 0; i < values.size(); ++i) { + v[i] = values[i]; + } + } else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<DataType, ValueT>) { + for (size_t i = 0; i < values.size(); ++i) { + v[i] = static_cast<DataType>(values[i]); + } + } else if constexpr (std::is_same_v<ValueT, std::string>) { + if constexpr (std::is_arithmetic_v<DataType>) { + for (size_t i = 0; i < values.size(); ++i) { + v[i] = std::to_string(values[i]); + } + } else { + for (size_t i = 0; i < values.size(); ++i) { + std::ostringstream sout; + sout << values[i] << std::ends; + v[i] = sout.str(); + } + } + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: unexpected right hand side type in tuple affectation", + m_node.children[1]->begin()); + // LCOV_EXCL_STOP + } + + *m_lhs = std::move(v); + } + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + static_assert(std::is_same_v<OperatorT, language::eq_op>, "forbidden affection operator for list to tuple"); + + std::visit( + [&](auto&& value_list) { + using ValueListT = std::decay_t<decltype(value_list)>; + if constexpr (std::is_same_v<AggregateDataVariant, ValueListT>) { + this->_copyAggregateDataVariant(value_list); + } else if constexpr (is_std_vector_v<ValueListT>) { + this->_copyVector(value_list); + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid lhs (expecting list or tuple)", + std::vector{m_node.children[1]->begin()}); + // LCOV_EXCL_STOP + } + }, + m_node.children[1]->execute(exec_policy)); + + return {}; + } + + AffectationToTupleFromListProcessor(ASTNode& node) : m_node{node} + { + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin()); + Assert(found); + + m_lhs = &i_symbol->attributes().value(); + } +}; + +template <typename ValueT> +class AffectationFromZeroProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + DataVariant* m_lhs; + + public: + DataVariant + execute(ExecutionPolicy&) + { + *m_lhs = ValueT{zero}; + return {}; + } + + AffectationFromZeroProcessor(ASTNode& node) : m_node{node} + { + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin()); + Assert(found); + + m_lhs = &i_symbol->attributes().value(); + } +}; + +template <typename OperatorT> +class ListAffectationProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + std::vector<std::unique_ptr<IAffectationExecutor>> m_affectation_executor_list; + + public: + template <typename ValueT, typename DataT> + void + add(ASTNode& lhs_node) + { + using AffectationExecutorT = AffectationExecutor<OperatorT, ValueT, DataT>; + + if (lhs_node.is_type<language::name>()) { + const std::string& symbol = lhs_node.string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->end()); + Assert(found); + DataVariant& value = i_symbol->attributes().value(); + + if (not std::holds_alternative<ValueT>(value)) { + value = ValueT{}; + } + + m_affectation_executor_list.emplace_back(std::make_unique<AffectationExecutorT>(m_node, std::get<ValueT>(value))); + } else if (lhs_node.is_type<language::subscript_expression>()) { + auto& array_subscript_expression = lhs_node; + + auto& array_expression = *array_subscript_expression.children[0]; + Assert(array_expression.is_type<language::name>()); + + const std::string& symbol = array_expression.string(); + + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, array_subscript_expression.begin()); + Assert(found); + DataVariant& value = i_symbol->attributes().value(); + + if (array_expression.m_data_type != ASTNodeDataType::vector_t) { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid lhs (expecting R^d)", + std::vector{array_subscript_expression.begin()}); + // LCOV_EXCL_STOP + } + + auto& index_expression = *array_subscript_expression.children[1]; + + switch (array_expression.m_data_type.dimension()) { + case 1: { + using ArrayTypeT = TinyVector<1>; + if (not std::holds_alternative<ArrayTypeT>(value)) { + value = ArrayTypeT{}; + } + using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>; + m_affectation_executor_list.emplace_back( + std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index_expression)); + break; + } + case 2: { + using ArrayTypeT = TinyVector<2>; + if (not std::holds_alternative<ArrayTypeT>(value)) { + value = ArrayTypeT{}; + } + using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>; + m_affectation_executor_list.emplace_back( + std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index_expression)); + break; + } + case 3: { + using ArrayTypeT = TinyVector<3>; + if (not std::holds_alternative<ArrayTypeT>(value)) { + value = ArrayTypeT{}; + } + using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>; + m_affectation_executor_list.emplace_back( + std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index_expression)); + break; + } + // LCOV_EXCL_START + default: { + throw parse_error("unexpected error: invalid vector dimension", + std::vector{array_subscript_expression.begin()}); + } + // LCOV_EXCL_STOP + } + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid left hand side", std::vector{lhs_node.begin()}); + // LCOV_EXCL_STOP + } + } + + DataVariant + execute(ExecutionPolicy& exec_policy) + { + AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy)); + Assert(m_affectation_executor_list.size() == children_values.size()); + + for (size_t i = 0; i < m_affectation_executor_list.size(); ++i) { + m_affectation_executor_list[i]->affect(exec_policy, std::move(children_values[i])); + } + + return {}; + } + + ListAffectationProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // AFFECTATION_PROCESSOR_HPP diff --git a/src/language/node_processor/ArraySubscriptProcessor.hpp b/src/language/node_processor/ArraySubscriptProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4853c65d326657a63599d62fc9d52713a96d1d5f --- /dev/null +++ b/src/language/node_processor/ArraySubscriptProcessor.hpp @@ -0,0 +1,51 @@ +#ifndef ARRAY_SUBSCRIPT_PROCESSOR_HPP +#define ARRAY_SUBSCRIPT_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +template <typename ArrayTypeT> +class ArraySubscriptProcessor : public INodeProcessor +{ + private: + ASTNode& m_array_subscript_expression; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + auto& index_expression = *m_array_subscript_expression.children[1]; + + const int64_t index_value = [&](DataVariant&& value_variant) -> int64_t { + int64_t index_value = 0; + std::visit( + [&](auto&& value) { + using ValueT = std::decay_t<decltype(value)>; + if constexpr (std::is_integral_v<ValueT>) { + index_value = value; + } else { + // LCOV_EXCL_START + throw parse_error("unexpected error: invalid index type", std::vector{index_expression.begin()}); + // LCOV_EXCL_STOP + } + }, + value_variant); + return index_value; + }(index_expression.execute(exec_policy)); + + auto& array_expression = *m_array_subscript_expression.children[0]; + + auto&& array_value = array_expression.execute(exec_policy); + ArrayTypeT& array = std::get<ArrayTypeT>(array_value); + + return array[index_value]; + } + + ArraySubscriptProcessor(ASTNode& array_subscript_expression) + : m_array_subscript_expression{array_subscript_expression} + {} + + virtual ~ArraySubscriptProcessor() = default; +}; + +#endif // ARRAY_SUBSCRIPT_PROCESSOR_HPP diff --git a/src/language/node_processor/BinaryExpressionProcessor.hpp b/src/language/node_processor/BinaryExpressionProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2e4fcef12ffe74dcd5cf972b4353ba88ab8d0e55 --- /dev/null +++ b/src/language/node_processor/BinaryExpressionProcessor.hpp @@ -0,0 +1,220 @@ +#ifndef BINARY_EXPRESSION_PROCESSOR_HPP +#define BINARY_EXPRESSION_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +template <typename Op> +struct BinOp; + +template <> +struct BinOp<language::and_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a and b) + { + return a and b; + } +}; + +template <> +struct BinOp<language::or_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a or b) + { + return a or b; + } +}; + +template <> +struct BinOp<language::xor_op> +{ + // C++ xor returns bitwise xor integer. Here we want to just test if one and + // only one of {a,b} is true so we enforce a bool cast + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> bool + { + return a xor b; + } +}; + +template <> +struct BinOp<language::eqeq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a == b) + { + return a == b; + } +}; + +template <> +struct BinOp<language::not_eq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a != b) + { + return a != b; + } +}; + +template <> +struct BinOp<language::lesser_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a < b) + { + return a < b; + } +}; + +template <> +struct BinOp<language::lesser_or_eq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a <= b) + { + return a <= b; + } +}; + +template <> +struct BinOp<language::greater_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a > b) + { + return a > b; + } +}; + +template <> +struct BinOp<language::greater_or_eq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a >= b) + { + return a >= b; + } +}; + +template <> +struct BinOp<language::plus_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a + b) + { + return a + b; + } +}; + +template <> +struct BinOp<language::minus_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a - b) + { + return a - b; + } +}; + +template <> +struct BinOp<language::multiply_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a * b) + { + return a * b; + } +}; + +template <> +struct BinOp<language::divide_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a / b) + { + return a / b; + } +}; + +template <typename BinaryOpT, typename A_DataT, typename B_DataT> +class BinaryExpressionProcessor final : public INodeProcessor +{ + ASTNode& m_node; + + PUGS_INLINE DataVariant + _eval(const DataVariant& a, const DataVariant& b) + { + // Add 'signed' when necessary to avoid signed/unsigned comparison warnings + if constexpr ((not(std::is_same_v<A_DataT, bool> or std::is_same_v<B_DataT, bool>)) and + (std::is_same_v<BinaryOpT, language::and_op> or std::is_same_v<BinaryOpT, language::or_op> or + std::is_same_v<BinaryOpT, language::xor_op> or std::is_same_v<BinaryOpT, language::eqeq_op> or + std::is_same_v<BinaryOpT, language::not_eq_op> or std::is_same_v<BinaryOpT, language::lesser_op> or + std::is_same_v<BinaryOpT, language::lesser_or_eq_op> or + std::is_same_v<BinaryOpT, language::greater_op> or + std::is_same_v<BinaryOpT, language::greater_or_eq_op>) and + (std::is_signed_v<A_DataT> xor std::is_signed_v<B_DataT>)) { + if constexpr (std::is_unsigned_v<A_DataT>) { + using signed_A_DataT = std::make_signed_t<A_DataT>; + const signed_A_DataT signed_a = static_cast<signed_A_DataT>(std::get<A_DataT>(a)); + return BinOp<BinaryOpT>().eval(signed_a, std::get<B_DataT>(b)); + } else { + using signed_B_DataT = std::make_signed_t<B_DataT>; + const signed_B_DataT signed_b = static_cast<signed_B_DataT>(std::get<B_DataT>(b)); + return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b); + } + } else { + auto result = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b)); + if constexpr (std::is_same_v<decltype(result), int>) { + return static_cast<int64_t>(result); + } else { + return result; + } + } + } + + static inline const bool m_is_defined{[] { + if constexpr (std::is_same_v<BinaryOpT, language::xor_op>) { + return std::is_same_v<std::decay_t<A_DataT>, std::decay_t<B_DataT>> and std::is_integral_v<std::decay_t<A_DataT>>; + } + return true; + }()}; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + if constexpr (m_is_defined) { + return this->_eval(m_node.children[0]->execute(exec_policy), m_node.children[1]->execute(exec_policy)); + } else { + return {}; // LCOV_EXCL_LINE + } + } + + BinaryExpressionProcessor(ASTNode& node) : m_node{node} + { + if constexpr (not m_is_defined) { + // LCOV_EXCL_START + throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()}); + // LCOV_EXCL_STOP + } + } +}; + +#endif // BINARY_EXPRESSION_PROCESSOR_HPP diff --git a/src/language/node_processor/BreakProcessor.hpp b/src/language/node_processor/BreakProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6f6d4a306c99723ab2e5ce7f4fc4864eebd77926 --- /dev/null +++ b/src/language/node_processor/BreakProcessor.hpp @@ -0,0 +1,19 @@ +#ifndef BREAK_PROCESSOR_HPP +#define BREAK_PROCESSOR_HPP + +#include <language/node_processor/INodeProcessor.hpp> + +class BreakProcessor final : public INodeProcessor +{ + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + exec_policy = ExecutionPolicy(exec_policy, ExecutionPolicy::JumpType::break_jump); + return {}; + } + + BreakProcessor() = default; +}; + +#endif // BREAK_PROCESSOR_HPP diff --git a/src/language/node_processor/BuiltinFunctionProcessor.hpp b/src/language/node_processor/BuiltinFunctionProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..755680f5fee0a2da69e02f0fd04a550e7e971846 --- /dev/null +++ b/src/language/node_processor/BuiltinFunctionProcessor.hpp @@ -0,0 +1,80 @@ +#ifndef BUILTIN_FUNCTION_PROCESSOR_HPP +#define BUILTIN_FUNCTION_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/FunctionArgumentConverter.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> + +#include <utils/SignalManager.hpp> + +class BuiltinFunctionExpressionProcessor final : public INodeProcessor +{ + private: + std::shared_ptr<IBuiltinFunctionEmbedder> m_embedded; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + return m_embedded->apply(exec_policy.currentContext().values()); + } + + BuiltinFunctionExpressionProcessor(std::shared_ptr<IBuiltinFunctionEmbedder> embedded) : m_embedded(embedded) {} +}; + +class BuiltinFunctionProcessor : public INodeProcessor +{ + private: + ASTNode& m_argument_node; + + std::unique_ptr<INodeProcessor> m_function_expression_processor; + + std::vector<std::unique_ptr<IFunctionArgumentConverter>> m_argument_converters; + + public: + void + addArgumentConverter(std::unique_ptr<IFunctionArgumentConverter>&& argument_converter) + { + m_argument_converters.emplace_back(std::move(argument_converter)); + } + + void + setFunctionExpressionProcessor(std::unique_ptr<INodeProcessor>&& function_processor) + { + m_function_expression_processor = std::move(function_processor); + } + + DataVariant + execute(ExecutionPolicy& exec_policy) + { + ExecutionPolicy context_exec_policy{exec_policy, + ExecutionPolicy::Context{-1, std::make_shared<ExecutionPolicy::Context::Values>( + m_argument_converters.size())}}; + if (m_argument_converters.size() == 1) { + m_argument_converters[0]->convert(context_exec_policy, m_argument_node.execute(context_exec_policy)); + } else { + AggregateDataVariant argument_values{ + std::get<AggregateDataVariant>(m_argument_node.execute(context_exec_policy))}; + + for (size_t i = 0; i < m_argument_converters.size(); ++i) { + m_argument_converters[i]->convert(context_exec_policy, std::move(argument_values[i])); + } + } + + if (SignalManager::pauseOnError()) { + return m_function_expression_processor->execute(context_exec_policy); + } else { + try { + return m_function_expression_processor->execute(context_exec_policy); + } + catch (std::runtime_error& e) { + throw parse_error(e.what(), {m_argument_node.begin()}); + } + } + } + + BuiltinFunctionProcessor(ASTNode& argument_node) : m_argument_node{argument_node} {} +}; + +#endif // BUILTIN_FUNCTION_PROCESSOR_HPP diff --git a/src/language/node_processor/CMakeLists.txt b/src/language/node_processor/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..adc3b3876b851016dfe5031f2eb939d4cbeff6aa --- /dev/null +++ b/src/language/node_processor/CMakeLists.txt @@ -0,0 +1,5 @@ +# ------------------- Source files -------------------- + +#add_library( +# PugsLanguageNodeProcessor +#) diff --git a/src/language/node_processor/ConcatExpressionProcessor.hpp b/src/language/node_processor/ConcatExpressionProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e47178494fe2bf88f8c7e5bebf9455c58732b08e --- /dev/null +++ b/src/language/node_processor/ConcatExpressionProcessor.hpp @@ -0,0 +1,35 @@ +#ifndef CONCAT_EXPRESSION_PROCESSOR_HPP +#define CONCAT_EXPRESSION_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +template <typename B_DataT> +class ConcatExpressionProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + PUGS_INLINE + DataVariant + _eval(const std::string& a, const DataVariant& b) + { + if constexpr (std::is_same_v<B_DataT, std::string>) { + return a + std::get<B_DataT>(b); + } else { + return a + std::to_string(std::get<B_DataT>(b)); + } + } + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + return this->_eval(std::get<std::string>(m_node.children[0]->execute(exec_policy)), + m_node.children[1]->execute(exec_policy)); + } + + ConcatExpressionProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // CONCAT_EXPRESSION_PROCESSOR_HPP diff --git a/src/language/node_processor/ContinueProcessor.hpp b/src/language/node_processor/ContinueProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e8e5d6c7daf807c94986ea58f40e327a60f5a7a4 --- /dev/null +++ b/src/language/node_processor/ContinueProcessor.hpp @@ -0,0 +1,19 @@ +#ifndef CONTINUE_PROCESSOR_HPP +#define CONTINUE_PROCESSOR_HPP + +#include <language/node_processor/INodeProcessor.hpp> + +class ContinueProcessor final : public INodeProcessor +{ + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + exec_policy = ExecutionPolicy(exec_policy, ExecutionPolicy::JumpType::continue_jump); + return {}; + } + + ContinueProcessor() = default; +}; + +#endif // CONTINUE_PROCESSOR_HPP diff --git a/src/language/node_processor/DoWhileProcessor.hpp b/src/language/node_processor/DoWhileProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5b03b769ffe3e376c5e8bddafa91db5d01e2f59f --- /dev/null +++ b/src/language/node_processor/DoWhileProcessor.hpp @@ -0,0 +1,48 @@ +#ifndef DO_WHILE_PROCESSOR_HPP +#define DO_WHILE_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class DoWhileProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + bool continuation_test = true; + ExecutionPolicy exec_until_jump; + do { + m_node.children[0]->execute(exec_until_jump); + if (not exec_until_jump.exec()) { + if (exec_until_jump.jumpType() == ExecutionPolicy::JumpType::break_jump) { + break; + } else if (exec_until_jump.jumpType() == ExecutionPolicy::JumpType::continue_jump) { + exec_until_jump = ExecutionPolicy{}; // getting ready for next loop traversal + } + } + + ; + continuation_test = static_cast<bool>(std::visit( + [](auto&& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_arithmetic_v<T>) { + return value; + } else { + return false; // LCOV_EXCL_LINE (unreachable: only there for compilation purpose) + } + }, + m_node.children[1]->execute(exec_policy))); + } while (continuation_test); + + m_node.children[0]->m_symbol_table->clearValues(); + return {}; + } + + DoWhileProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // DO_WHILE_PROCESSOR_HPP diff --git a/src/language/node_processor/ExecutionPolicy.hpp b/src/language/node_processor/ExecutionPolicy.hpp new file mode 100644 index 0000000000000000000000000000000000000000..47fc3174ca5236c067bde9045a97f4d1c0fe160a --- /dev/null +++ b/src/language/node_processor/ExecutionPolicy.hpp @@ -0,0 +1,122 @@ +#ifndef EXECUTION_POLICY_HPP +#define EXECUTION_POLICY_HPP + +#include <language/utils/DataVariant.hpp> +#include <utils/PugsMacros.hpp> + +#include <memory> +#include <vector> + +class ExecutionPolicy +{ + public: + enum class JumpType + { + no_jump, + break_jump, + continue_jump + }; + + class Context + { + public: + using Values = std::vector<DataVariant>; + using SharedValues = std::shared_ptr<Values>; + + private: + int32_t m_id; + SharedValues m_shared_values; + + public: + auto + size() const + { + return m_shared_values->size(); + } + + DataVariant& operator[](size_t i) + { + return (*m_shared_values)[i]; + } + + const DataVariant& operator[](size_t i) const + { + return (*m_shared_values)[i]; + } + + const Values& + values() const + { + return *m_shared_values; + } + + int32_t + id() const + { + return m_id; + } + + Context(int32_t id, const SharedValues& shared_values) : m_id{id}, m_shared_values{shared_values} {} + + Context(const Context&) = default; + }; + + private: + JumpType m_jump_type; + bool m_exec; + + std::vector<Context> m_context_list; + + public: + PUGS_INLINE + bool + exec() const + { + return m_exec; + } + + PUGS_INLINE + JumpType + jumpType() const + { + return m_jump_type; + } + + Context& + contextOfId(int32_t context_id) + { + for (auto i_context = m_context_list.rbegin(); i_context != m_context_list.rend(); ++i_context) { + if (i_context->id() == context_id) { + return *i_context; + } + } + throw std::invalid_argument{"unable to find context"}; + } + + Context& + currentContext() + { + return m_context_list.back(); + } + + ExecutionPolicy& operator=(const ExecutionPolicy&) = delete; + ExecutionPolicy& operator=(ExecutionPolicy&&) = default; + + explicit ExecutionPolicy(const ExecutionPolicy&) = default; + ExecutionPolicy(ExecutionPolicy&&) = default; + + ExecutionPolicy() : m_jump_type{JumpType::no_jump}, m_exec{true} {} + + ExecutionPolicy(const ExecutionPolicy& parent_policy, const Context& context) : ExecutionPolicy{parent_policy} + { + m_context_list.push_back(context); + } + + ExecutionPolicy(const ExecutionPolicy& parent_policy, JumpType jump_type) + : m_jump_type{jump_type}, m_exec{jump_type == JumpType::no_jump}, m_context_list{parent_policy.m_context_list} + { + ; + } +}; + +#endif // EXECUTION_POLICY_HPP diff --git a/src/language/node_processor/FakeProcessor.hpp b/src/language/node_processor/FakeProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ce3b7d257aa8d3684fd06ff87496ce1b66fa9bf5 --- /dev/null +++ b/src/language/node_processor/FakeProcessor.hpp @@ -0,0 +1,18 @@ +#ifndef FAKE_PROCESSOR_HPP +#define FAKE_PROCESSOR_HPP + +#include <language/node_processor/INodeProcessor.hpp> + +class FakeProcessor final : public INodeProcessor +{ + public: + DataVariant + execute(ExecutionPolicy&) + { + return {}; + } + + FakeProcessor() = default; +}; + +#endif // FAKE_PROCESSOR_HPP diff --git a/src/language/node_processor/ForProcessor.hpp b/src/language/node_processor/ForProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8680aaf7ded0f7fabbc345682a9a32c772a44f08 --- /dev/null +++ b/src/language/node_processor/ForProcessor.hpp @@ -0,0 +1,49 @@ +#ifndef FOR_PROCESSOR_HPP +#define FOR_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class ForProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + ExecutionPolicy exec_until_jump; + m_node.children[0]->execute(exec_policy); + while ([&]() { + return static_cast<bool>(std::visit( + [](auto&& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_arithmetic_v<T>) { + return value; + } else { + return false; // LCOV_EXCL_LINE (unreachable: only there for compilation purpose) + } + }, + m_node.children[1]->execute(exec_policy))); + }()) { + m_node.children[3]->execute(exec_until_jump); + if (not exec_until_jump.exec()) { + if (exec_until_jump.jumpType() == ExecutionPolicy::JumpType::break_jump) { + break; + } else if (exec_until_jump.jumpType() == ExecutionPolicy::JumpType::continue_jump) { + exec_until_jump = ExecutionPolicy{}; // getting ready for next loop traversal + } + } + + m_node.children[2]->execute(exec_policy); + } + + m_node.m_symbol_table->clearValues(); + return {}; + } + + ForProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // FOR_PROCESSOR_HPP diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4bf7e56eebfd93b244d13a774e2e69aac2834794 --- /dev/null +++ b/src/language/node_processor/FunctionArgumentConverter.hpp @@ -0,0 +1,234 @@ +#ifndef FUNCTION_ARGUMENT_CONVERTER_HPP +#define FUNCTION_ARGUMENT_CONVERTER_HPP + +#include <language/node_processor/ExecutionPolicy.hpp> +#include <language/utils/DataVariant.hpp> +#include <utils/Demangle.hpp> +#include <utils/Exceptions.hpp> +#include <utils/PugsTraits.hpp> + +#include <sstream> + +class IFunctionArgumentConverter +{ + public: + virtual DataVariant convert(ExecutionPolicy& exec_policy, DataVariant&& value) = 0; + + IFunctionArgumentConverter() = default; + + IFunctionArgumentConverter(const IFunctionArgumentConverter&) = delete; + IFunctionArgumentConverter(IFunctionArgumentConverter&&) = delete; + + virtual ~IFunctionArgumentConverter() = default; +}; + +class FunctionArgumentToStringConverter final : public IFunctionArgumentConverter +{ + private: + size_t m_argument_id; + + public: + DataVariant + convert(ExecutionPolicy& exec_policy, DataVariant&& value) + { + std::ostringstream sout; + sout << value; + exec_policy.currentContext()[m_argument_id] = sout.str(); + return {}; + } + + FunctionArgumentToStringConverter(size_t argument_id) : m_argument_id{argument_id} {} +}; + +template <typename ExpectedValueType, typename ProvidedValueType> +class FunctionArgumentConverter final : public IFunctionArgumentConverter +{ + private: + size_t m_argument_id; + + public: + DataVariant + convert(ExecutionPolicy& exec_policy, DataVariant&& value) + { + static_assert(not std::is_same_v<ExpectedValueType, std::string>, "use FunctionArgumentToStringConverter"); + if constexpr (std::is_same_v<ExpectedValueType, ProvidedValueType>) { + exec_policy.currentContext()[m_argument_id] = std::move(value); + } else { + exec_policy.currentContext()[m_argument_id] = + std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value))); + } + return {}; + } + + FunctionArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {} +}; + +template <typename ExpectedValueType, typename ProvidedValueType> +class FunctionTinyVectorArgumentConverter final : public IFunctionArgumentConverter +{ + private: + size_t m_argument_id; + + public: + DataVariant + convert(ExecutionPolicy& exec_policy, DataVariant&& value) + { + if constexpr (std::is_same_v<ExpectedValueType, ProvidedValueType>) { + std::visit( + [&](auto&& v) { + using ValueT = std::decay_t<decltype(v)>; + if constexpr (std::is_same_v<ValueT, ExpectedValueType>) { + exec_policy.currentContext()[m_argument_id] = std::move(value); + } else if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) { + ExpectedValueType vector_value{}; + for (size_t i = 0; i < vector_value.dimension(); ++i) { + std::visit( + [&](auto&& v_i) { + using Vi_T = std::decay_t<decltype(v_i)>; + if constexpr (std::is_arithmetic_v<Vi_T>) { + vector_value[i] = v_i; + } else { + throw UnexpectedError(demangle<Vi_T>() + " unexpected aggregate value type"); + } + }, + v[i]); + } + exec_policy.currentContext()[m_argument_id] = std::move(vector_value); + } + }, + value); + } else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero}; + } else { + exec_policy.currentContext()[m_argument_id] = + std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value))); + } + return {}; + } + + FunctionTinyVectorArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {} +}; + +template <typename ContentType, typename ProvidedValueType> +class FunctionTupleArgumentConverter final : public IFunctionArgumentConverter +{ + private: + size_t m_argument_id; + + public: + DataVariant + convert(ExecutionPolicy& exec_policy, DataVariant&& value) + { + using TupleType = std::vector<ContentType>; + if constexpr (std::is_convertible_v<ProvidedValueType, ContentType>) { + std::visit( + [&](auto&& v) { + using ValueT = std::decay_t<decltype(v)>; + if constexpr (std::is_same_v<ValueT, ContentType>) { + exec_policy.currentContext()[m_argument_id] = std::move(TupleType{std::move(v)}); + } else if constexpr (is_std_vector_v<ValueT>) { + using ContentT = typename ValueT::value_type; + if constexpr (std::is_same_v<ContentT, ContentType>) { + TupleType list_value; + list_value.reserve(v.size()); + for (size_t i = 0; i < v.size(); ++i) { + list_value.emplace_back(v[i]); + } + exec_policy.currentContext()[m_argument_id] = std::move(list_value); + } + } else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ContentType>) { + exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)}); + } else { + throw UnexpectedError(demangle<ValueT>() + " unexpected value type"); + } + }, + value); + } else { + throw UnexpectedError(demangle<std::decay_t<decltype(*this)>>() + ": did nothing!"); + } + return {}; + } + + FunctionTupleArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {} +}; + +template <typename ContentType, typename ProvidedValueType> +class FunctionListArgumentConverter final : public IFunctionArgumentConverter +{ + private: + size_t m_argument_id; + + public: + DataVariant + convert(ExecutionPolicy& exec_policy, DataVariant&& value) + { + using TupleType = std::vector<ContentType>; + if constexpr (std::is_same_v<ContentType, ProvidedValueType>) { + std::visit( + [&](auto&& v) { + using ValueT = std::decay_t<decltype(v)>; + if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) { + TupleType list_value; + list_value.reserve(v.size()); + for (size_t i = 0; i < v.size(); ++i) { + std::visit( + [&](auto&& vi) { + using Vi_T = std::decay_t<decltype(vi)>; + if constexpr (is_tiny_vector_v<ContentType>) { + throw NotImplementedError("TinyVector case"); + } else if constexpr (std::is_convertible_v<Vi_T, ContentType>) { + list_value.emplace_back(vi); + } else { + throw UnexpectedError("unexpected types"); + } + }, + (v[i])); + } + exec_policy.currentContext()[m_argument_id] = std::move(list_value); + } else if constexpr (std::is_same_v<ValueT, ContentType>) { + exec_policy.currentContext()[m_argument_id] = std::move(v); + } else if constexpr (is_std_vector_v<ValueT>) { + using ContentT = typename ValueT::value_type; + if constexpr (std::is_same_v<ContentT, ContentType>) { + TupleType list_value; + list_value.reserve(v.size()); + for (size_t i = 0; i < v.size(); ++i) { + list_value.emplace_back(v[i]); + } + exec_policy.currentContext()[m_argument_id] = std::move(list_value); + } + } else { + throw UnexpectedError(demangle<ValueT>() + " unexpected value type"); + } + }, + value); + } + static_assert(std::is_same_v<ContentType, ProvidedValueType>, "conversion is not implemented"); + + return {}; + } + + FunctionListArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {} +}; + +class FunctionArgumentToFunctionSymbolIdConverter final : public IFunctionArgumentConverter +{ + private: + size_t m_argument_id; + std::shared_ptr<SymbolTable> m_symbol_table; + + public: + DataVariant + convert(ExecutionPolicy& exec_policy, DataVariant&& value) + { + exec_policy.currentContext()[m_argument_id] = FunctionSymbolId{std::get<uint64_t>(value), m_symbol_table}; + + return {}; + } + + FunctionArgumentToFunctionSymbolIdConverter(size_t argument_id, const std::shared_ptr<SymbolTable>& symbol_table) + : m_argument_id{argument_id}, m_symbol_table{symbol_table} + {} +}; + +#endif // FUNCTION_ARGUMENT_CONVERTER_HPP diff --git a/src/language/node_processor/FunctionProcessor.hpp b/src/language/node_processor/FunctionProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b28c2ce499538818ce60b1ac36a1d158114409de --- /dev/null +++ b/src/language/node_processor/FunctionProcessor.hpp @@ -0,0 +1,115 @@ +#ifndef FUNCTION_PROCESSOR_HPP +#define FUNCTION_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/ASTNodeExpressionListProcessor.hpp> +#include <language/node_processor/FunctionArgumentConverter.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/FunctionTable.hpp> +#include <language/utils/SymbolTable.hpp> + +template <typename ReturnType, typename ExpressionValueType> +class FunctionExpressionProcessor final : public INodeProcessor +{ + private: + ASTNode& m_function_expression; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + if constexpr (std::is_same_v<ReturnType, ExpressionValueType>) { + return m_function_expression.execute(exec_policy); + } else if constexpr (std::is_same_v<AggregateDataVariant, ExpressionValueType>) { + static_assert(is_tiny_vector_v<ReturnType>, "unexpected return type"); + ReturnType return_value{}; + auto value = std::get<ExpressionValueType>(m_function_expression.execute(exec_policy)); + for (size_t i = 0; i < ReturnType::Dimension; ++i) { + std::visit( + [&](auto&& vi) { + using Vi_T = std::decay_t<decltype(vi)>; + if constexpr (std::is_convertible_v<Vi_T, double>) { + return_value[i] = vi; + } + }, + value[i]); + } + return return_value; + } else if constexpr (std::is_same_v<ReturnType, std::string>) { + return std::to_string(std::get<ExpressionValueType>(m_function_expression.execute(exec_policy))); + } else if constexpr (std::is_same_v<ExpressionValueType, ZeroType>) { + return ReturnType{ZeroType::zero}; + } else if constexpr (std::is_convertible_v<ExpressionValueType, ReturnType>) { + return static_cast<ReturnType>(std::get<ExpressionValueType>(m_function_expression.execute(exec_policy))); + } else { + throw UnexpectedError("invalid conversion"); + } + } + + FunctionExpressionProcessor(ASTNode& function_component_expression) + : m_function_expression{function_component_expression} + {} +}; + +class FunctionProcessor : public INodeProcessor +{ + private: + ASTNode& m_argument_node; + + const size_t m_context_size; + const int32_t m_context_id; + + std::vector<std::unique_ptr<IFunctionArgumentConverter>> m_argument_converters; + std::vector<std::unique_ptr<INodeProcessor>> m_function_expression_processors; + + public: + void + addArgumentConverter(std::unique_ptr<IFunctionArgumentConverter>&& argument_converter) + { + m_argument_converters.emplace_back(std::move(argument_converter)); + } + + void + addFunctionExpressionProcessor(std::unique_ptr<INodeProcessor>&& function_processor) + { + m_function_expression_processors.emplace_back(std::move(function_processor)); + } + + DataVariant + execute(ExecutionPolicy& exec_policy) + { + // Context is built in each execution for thread safety: multiple thread can call a function at once + ExecutionPolicy::Context context{m_context_id, std::make_shared<ExecutionPolicy::Context::Values>(m_context_size)}; + + ExecutionPolicy context_exec_policy{exec_policy, context}; + + if (m_argument_converters.size() == 1) { + m_argument_converters[0]->convert(context_exec_policy, m_argument_node.execute(context_exec_policy)); + } else { + AggregateDataVariant argument_values{ + std::get<AggregateDataVariant>(m_argument_node.execute(context_exec_policy))}; + + for (size_t i = 0; i < m_argument_converters.size(); ++i) { + m_argument_converters[i]->convert(context_exec_policy, std::move(argument_values[i])); + } + } + + if (m_function_expression_processors.size() == 1) { + return m_function_expression_processors[0]->execute(context_exec_policy); + } else { + std::vector<DataVariant> list_values; + list_values.reserve(m_function_expression_processors.size()); + + for (auto& function_expression_processor : m_function_expression_processors) { + list_values.emplace_back(function_expression_processor->execute(context_exec_policy)); + } + return DataVariant{std::move(list_values)}; + } + } + + FunctionProcessor(ASTNode& argument_node, SymbolTable::Context context) + : m_argument_node{argument_node}, m_context_size{context.size()}, m_context_id{context.id()} + {} +}; + +#endif // FUNCTION_PROCESSOR_HPP diff --git a/src/language/node_processor/INodeProcessor.hpp b/src/language/node_processor/INodeProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ce06b9484f7c7b141861bddfc88f5b5c3bf9eecc --- /dev/null +++ b/src/language/node_processor/INodeProcessor.hpp @@ -0,0 +1,29 @@ +#ifndef I_NODE_PROCESSOR_HPP +#define I_NODE_PROCESSOR_HPP + +#include <language/node_processor/ExecutionPolicy.hpp> +#include <language/utils/DataVariant.hpp> +#include <utils/Demangle.hpp> + +#include <string> +#include <typeinfo> + +struct INodeProcessor +{ + virtual DataVariant execute(ExecutionPolicy& exec_policy) = 0; + + std::string + typeIdName() const + { + return demangle(typeid(*this).name()); + } + + INodeProcessor(const INodeProcessor&) = delete; + INodeProcessor(INodeProcessor&&) = delete; + + INodeProcessor() = default; + + virtual ~INodeProcessor() = default; +}; + +#endif // I_NODE_PROCESSOR_HPP diff --git a/src/language/node_processor/IfProcessor.hpp b/src/language/node_processor/IfProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1a76e3068dcb6bd29f4e4e250dc3d6cc1f9f6d41 --- /dev/null +++ b/src/language/node_processor/IfProcessor.hpp @@ -0,0 +1,50 @@ +#ifndef IF_PROCESSOR_HPP +#define IF_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class IfProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + const bool is_true = static_cast<bool>(std::visit( // LCOV_EXCL_LINE (false negative) + [](const auto& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_arithmetic_v<T>) { + return value; + } else { + return false; // LCOV_EXCL_LINE (unreachable: only there for compilation purpose) + } + }, + m_node.children[0]->execute(exec_policy))); + if (is_true) { + Assert(m_node.children[1] != nullptr); + m_node.children[1]->execute(exec_policy); + if (m_node.children[1]->m_symbol_table != m_node.m_symbol_table) + m_node.children[1]->m_symbol_table->clearValues(); + + } else { + if (m_node.children.size() == 3) { + // else statement + Assert(m_node.children[2] != nullptr); + m_node.children[2]->execute(exec_policy); + if (m_node.children[2]->m_symbol_table != m_node.m_symbol_table) + m_node.children[2]->m_symbol_table->clearValues(); + } + } + + if (m_node.children[0]->m_symbol_table != m_node.m_symbol_table) + m_node.children[0]->m_symbol_table->clearValues(); + return {}; + } + + IfProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // IF_PROCESSOR_HPP diff --git a/src/language/node_processor/IncDecExpressionProcessor.hpp b/src/language/node_processor/IncDecExpressionProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9e50106e5c531e8f5cd3dcd546bf131570c499c6 --- /dev/null +++ b/src/language/node_processor/IncDecExpressionProcessor.hpp @@ -0,0 +1,81 @@ +#ifndef INC_DEC_EXPRESSION_PROCESSOR_HPP +#define INC_DEC_EXPRESSION_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> + +template <typename Op> +struct IncDecOp; + +template <> +struct IncDecOp<language::unary_minusminus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return --a; + } +}; + +template <> +struct IncDecOp<language::unary_plusplus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return ++a; + } +}; + +template <> +struct IncDecOp<language::post_minusminus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return a--; + } +}; + +template <> +struct IncDecOp<language::post_plusplus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return a++; + } +}; + +template <typename IncDecOpT, typename DataT> +class IncDecExpressionProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + DataVariant* p_value{nullptr}; + + public: + DataVariant + execute(ExecutionPolicy&) + { + return IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value)); + } + + IncDecExpressionProcessor(ASTNode& node) : m_node{node} + { + Assert(m_node.children[0]->is_type<language::name>()); + // It is sure at this point that children 0 is a variable name + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin()); + Assert(found); + p_value = &i_symbol->attributes().value(); + } +}; + +#endif // INC_DEC_EXPRESSION_PROCESSOR_HPP diff --git a/src/language/node_processor/LocalNameProcessor.hpp b/src/language/node_processor/LocalNameProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51d442b266288360c1d5f6fe000ba72fa7057cb9 --- /dev/null +++ b/src/language/node_processor/LocalNameProcessor.hpp @@ -0,0 +1,32 @@ +#ifndef LOCAL_NODE_PROCESSOR_HPP +#define LOCAL_NODE_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> + +class LocalNameProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + uint64_t m_value_id; + int32_t m_context_id; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + return exec_policy.contextOfId(m_context_id)[m_value_id]; + } + + LocalNameProcessor(ASTNode& node) : m_node{node} + { + const std::string& symbol = m_node.string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.begin()); + Assert(found); + m_value_id = std::get<uint64_t>(i_symbol->attributes().value()); + m_context_id = i_symbol->attributes().contextId(); + } +}; + +#endif // LOCAL_NODE_PROCESSOR_HPP diff --git a/src/language/node_processor/NameProcessor.hpp b/src/language/node_processor/NameProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..53fee78ef7f1b9232100bbec8d3a7327c64d2078 --- /dev/null +++ b/src/language/node_processor/NameProcessor.hpp @@ -0,0 +1,30 @@ +#ifndef NODE_PROCESSOR_HPP +#define NODE_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> + +class NameProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + DataVariant* p_value{nullptr}; + + public: + DataVariant + execute(ExecutionPolicy&) + { + return *p_value; + } + + NameProcessor(ASTNode& node) : m_node{node} + { + const std::string& symbol = m_node.string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.begin()); + Assert(found); + p_value = &(i_symbol->attributes().value()); + } +}; + +#endif // NODE_PROCESSOR_HPP diff --git a/src/language/node_processor/OStreamProcessor.hpp b/src/language/node_processor/OStreamProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..606247653b397998fab2016b970d87637201c527 --- /dev/null +++ b/src/language/node_processor/OStreamProcessor.hpp @@ -0,0 +1,37 @@ +#ifndef OSTREAM_PROCESSOR_HPP +#define OSTREAM_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class OStreamProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + std::ostream& m_os; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + for (size_t i = 0; i < m_node.children.size(); ++i) { + m_os << m_node.children[i]->execute(exec_policy); + } + + return {}; + } + + OStreamProcessor(ASTNode& node, std::ostream& os) : m_node{node}, m_os(os) + { + for (auto& child : m_node.children) { + if ((child->m_data_type == ASTNodeDataType::type_name_id_t) or + (child->m_data_type == ASTNodeDataType::function_t) or + (child->m_data_type == ASTNodeDataType::builtin_function_t)) { + throw parse_error("invalid argument, cannot print a '" + dataTypeName(child->m_data_type) + "'", + std::vector{child->begin()}); + } + } + } +}; + +#endif // OSTREAM_PROCESSOR_HPP diff --git a/src/language/node_processor/TupleToTinyVectorProcessor.hpp b/src/language/node_processor/TupleToTinyVectorProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..da4f1e08dc0351e43df185e13415669f1ef26b44 --- /dev/null +++ b/src/language/node_processor/TupleToTinyVectorProcessor.hpp @@ -0,0 +1,51 @@ +#ifndef TUPLE_TO_TINY_VECTOR_PROCESSOR_HPP +#define TUPLE_TO_TINY_VECTOR_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +template <typename TupleProcessorT, size_t N> +class TupleToTinyVectorProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + std::unique_ptr<TupleProcessorT> m_tuple_processor; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + AggregateDataVariant v = std::get<AggregateDataVariant>(m_tuple_processor->execute(exec_policy)); + + Assert(v.size() == N); + + TinyVector<N> x; + + for (size_t i = 0; i < N; ++i) { + std::visit( + [&](auto&& v) { + using ValueT = std::decay_t<decltype(v)>; + if constexpr (std::is_arithmetic_v<ValueT>) { + x[i] = v; + } else { + // LCOV_EXCL_START + Assert(false, "unexpected value type"); + // LCOV_EXCL_STOP + } + }, + v[i]); + } + + return DataVariant{std::move(x)}; + } + + TupleToTinyVectorProcessor(ASTNode& node) : m_node{node}, m_tuple_processor{std::make_unique<TupleProcessorT>(node)} + {} + + TupleToTinyVectorProcessor(ASTNode& node, std::unique_ptr<TupleProcessorT>&& tuple_processor) + : m_node{node}, m_tuple_processor{std::move(tuple_processor)} + {} +}; + +#endif // TUPLE_TO_TINY_VECTOR_PROCESSOR_HPP diff --git a/src/language/node_processor/TupleToVectorProcessor.hpp b/src/language/node_processor/TupleToVectorProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..74ad59acb95e0e853a880fb171e93d77c55dcd74 --- /dev/null +++ b/src/language/node_processor/TupleToVectorProcessor.hpp @@ -0,0 +1,32 @@ +#ifndef TUPLE_TO_VECTOR_PROCESSOR_HPP +#define TUPLE_TO_VECTOR_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +template <typename TupleProcessorT> +class TupleToVectorProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + std::unique_ptr<TupleProcessorT> m_tuple_processor; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + AggregateDataVariant v = std::get<AggregateDataVariant>(m_tuple_processor->execute(exec_policy)); + + v.setIsFlattenable(false); + return v; + } + + TupleToVectorProcessor(ASTNode& node) : m_node{node}, m_tuple_processor{std::make_unique<TupleProcessorT>(node)} {} + + TupleToVectorProcessor(ASTNode& node, std::unique_ptr<TupleProcessorT>&& tuple_processor) + : m_node{node}, m_tuple_processor{std::move(tuple_processor)} + {} +}; + +#endif // TUPLE_TO_TINY_VECTOR_PROCESSOR_HPP diff --git a/src/language/node_processor/UnaryExpressionProcessor.hpp b/src/language/node_processor/UnaryExpressionProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c99c7f2dd828583c7dad8048338e68d26c807be2 --- /dev/null +++ b/src/language/node_processor/UnaryExpressionProcessor.hpp @@ -0,0 +1,55 @@ +#ifndef UNARY_EXPRESSION_PROCESSOR_HPP +#define UNARY_EXPRESSION_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> + +template <typename Op> +struct UnaryOp; + +template <> +struct UnaryOp<language::unary_minus> +{ + template <typename A> + PUGS_INLINE A + eval(const A& a) + { + return -a; + } +}; + +template <> +struct UnaryOp<language::unary_not> +{ + template <typename A> + PUGS_INLINE bool + eval(const A& a) + { + return not a; + } +}; + +template <typename UnaryOpT, typename ValueT, typename DataT> +class UnaryExpressionProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + PUGS_INLINE ValueT + _eval(const DataVariant& a) + { + return UnaryOp<UnaryOpT>().eval(static_cast<ValueT>(std::get<DataT>(a))); + } + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + return this->_eval(m_node.children[0]->execute(exec_policy)); + } + + UnaryExpressionProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // UNARY_EXPRESSION_PROCESSOR_HPP diff --git a/src/language/node_processor/ValueProcessor.hpp b/src/language/node_processor/ValueProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..342198223e763fdb66781a632da0d107182234d5 --- /dev/null +++ b/src/language/node_processor/ValueProcessor.hpp @@ -0,0 +1,48 @@ +#ifndef VALUE_PROCESSOR_HPP +#define VALUE_PROCESSOR_HPP + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> +#include <utils/EscapedString.hpp> + +class ValueProcessor final : public INodeProcessor +{ + private: + DataVariant m_value; + + public: + PUGS_INLINE + DataVariant + execute(ExecutionPolicy&) + { + return m_value; + } + + ValueProcessor(ASTNode& node) + { + if (node.is_type<language::real>()) { + std::stringstream ss(node.string()); + double v; + ss >> v; + m_value = v; + } else if (node.is_type<language::integer>()) { + std::stringstream ss(node.string()); + int64_t v; + ss >> v; + m_value = v; + } else if (node.is_type<language::literal>()) { + m_value = unescapeString(node.string()); + } else if (node.is_type<language::for_test>()) { + // if AST contains a for_test statement, it means that no test were + // given to the for-loop, so its value is always true + m_value = true; + } else if (node.is_type<language::true_kw>()) { + m_value = true; + } else if (node.is_type<language::false_kw>()) { + m_value = false; + } + } +}; + +#endif // VALUE_PROCESSOR_HPP diff --git a/src/language/node_processor/WhileProcessor.hpp b/src/language/node_processor/WhileProcessor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..20b0ac985ae43bfaf3f9b165f9a346aa82a9f3cb --- /dev/null +++ b/src/language/node_processor/WhileProcessor.hpp @@ -0,0 +1,46 @@ +#ifndef WHILE_PROCESSOR_HPP +#define WHILE_PROCESSOR_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/INodeProcessor.hpp> + +class WhileProcessor final : public INodeProcessor +{ + private: + ASTNode& m_node; + + public: + DataVariant + execute(ExecutionPolicy& exec_policy) + { + ExecutionPolicy exec_until_jump; + while ([&]() { + return static_cast<bool>(std::visit( + [](const auto& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_arithmetic_v<T>) { + return value; + } else { + return false; // LCOV_EXCL_LINE (unreachable: only there for compilation purpose) + } + }, + m_node.children[0]->execute(exec_policy))); + }()) { + m_node.children[1]->execute(exec_until_jump); + if (not exec_until_jump.exec()) { + if (exec_until_jump.jumpType() == ExecutionPolicy::JumpType::break_jump) { + break; + } else if (exec_until_jump.jumpType() == ExecutionPolicy::JumpType::continue_jump) { + exec_until_jump = ExecutionPolicy{}; // getting ready for next loop traversal + } + } + } + + m_node.children[1]->m_symbol_table->clearValues(); + return {}; + } + + WhileProcessor(ASTNode& node) : m_node{node} {} +}; + +#endif // WHILE_PROCESSOR_HPP diff --git a/src/language/utils/ASTDotPrinter.cpp b/src/language/utils/ASTDotPrinter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be0795198db278e68b6db7081773da7666fda1c7 --- /dev/null +++ b/src/language/utils/ASTDotPrinter.cpp @@ -0,0 +1,54 @@ +#include <language/utils/ASTDotPrinter.hpp> + +#include <language/PEGGrammar.hpp> +#include <utils/EscapedString.hpp> + +void +ASTDotPrinter::_print(std::ostream& os, const ASTNode& node) const +{ + if (node.is_root()) { + os << " x" << m_node_number_map.at(&node) << " [ label=\"root \\n" << dataTypeName(node.m_data_type) << "\" ]\n"; + } else { + if (node.has_content()) { + os << " x" << m_node_number_map.at(&node) << " [ label=\"" << node.name() << "\\n" + << escapeString(node.string_view()) << "\\n" + << dataTypeName(node.m_data_type) << "\" ]\n"; + } else { + os << " x" << m_node_number_map.at(&node) << " [ label=\"" << node.name() << "\\n" + << dataTypeName(node.m_data_type) << "\" ]\n"; + } + } + if (!node.children.empty()) { + os << " x" << m_node_number_map.at(&node) << " -> { "; + for (auto& child : node.children) { + os << "x" << m_node_number_map.at(child.get()) << ((child == node.children.back()) ? " }\n" : ", "); + } + for (auto& child : node.children) { + this->_print(os, *child); + } + } +} + +std::ostream& +operator<<(std::ostream& os, const ASTDotPrinter& ast_printer) +{ + os << "digraph parse_tree\n{\n"; + ast_printer._print(os, ast_printer.m_node); + os << "}\n"; + return os; +} + +void +ASTDotPrinter::_buildNodeNumberMap(const ASTNode& node) +{ + m_node_number_map[&node] = m_node_number_map.size(); + for (auto& child : node.children) { + this->_buildNodeNumberMap(*child); + } +} + +ASTDotPrinter::ASTDotPrinter(const ASTNode& node) : m_node{node} +{ + Assert(node.is_root()); + this->_buildNodeNumberMap(node); +} diff --git a/src/language/utils/ASTDotPrinter.hpp b/src/language/utils/ASTDotPrinter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ce7d4dd396a1a467c3e2e18a161156fea9294c6b --- /dev/null +++ b/src/language/utils/ASTDotPrinter.hpp @@ -0,0 +1,31 @@ +#ifndef AST_DOT_PRINTER_HPP +#define AST_DOT_PRINTER_HPP + +#include <language/ast/ASTNode.hpp> + +#include <map> + +class ASTDotPrinter +{ + private: + const ASTNode& m_node; + + std::map<const ASTNode*, uint32_t> m_node_number_map; + + void _print(std::ostream& os, const ASTNode& node) const; + + void _buildNodeNumberMap(const ASTNode& node); + + public: + friend std::ostream& operator<<(std::ostream& os, const ASTDotPrinter& ast_printer); + + ASTDotPrinter(const ASTNode& node); + + ASTDotPrinter(const ASTDotPrinter&) = delete; + + ASTDotPrinter(ASTDotPrinter&&) = delete; + + ~ASTDotPrinter() = default; +}; + +#endif // AST_DOT_PRINTER_HPP diff --git a/src/language/utils/ASTNodeDataTypeTraits.hpp b/src/language/utils/ASTNodeDataTypeTraits.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4ee3ba31bf60d3ca4f006fd0510fae0c1fc14056 --- /dev/null +++ b/src/language/utils/ASTNodeDataTypeTraits.hpp @@ -0,0 +1,34 @@ +#ifndef AST_NODE_DATA_TYPE_TRAITS_H +#define AST_NODE_DATA_TYPE_TRAITS_H + +#include <algebra/TinyVector.hpp> +#include <language/ast/ASTNodeDataType.hpp> +#include <language/utils/FunctionSymbolId.hpp> + +#include <vector> + +template <typename T> +inline ASTNodeDataType ast_node_data_type_from = ASTNodeDataType::undefined_t; + +template <> +inline ASTNodeDataType ast_node_data_type_from<void> = ASTNodeDataType::void_t; +template <> +inline ASTNodeDataType ast_node_data_type_from<bool> = ASTNodeDataType::bool_t; +template <> +inline ASTNodeDataType ast_node_data_type_from<int64_t> = ASTNodeDataType::int_t; +template <> +inline ASTNodeDataType ast_node_data_type_from<uint64_t> = ASTNodeDataType::unsigned_int_t; +template <> +inline ASTNodeDataType ast_node_data_type_from<double> = ASTNodeDataType::double_t; +template <> +inline ASTNodeDataType ast_node_data_type_from<std::string> = ASTNodeDataType::string_t; +template <> +inline ASTNodeDataType ast_node_data_type_from<FunctionSymbolId> = ASTNodeDataType::function_t; +template <size_t N> +inline ASTNodeDataType ast_node_data_type_from<TinyVector<N>> = {ASTNodeDataType::vector_t, N}; + +template <typename T> +inline ASTNodeDataType ast_node_data_type_from<std::vector<T>> = + ASTNodeDataType{ASTNodeDataType::tuple_t, ast_node_data_type_from<T>}; + +#endif // AST_NODE_DATA_TYPE_TRAITS_H diff --git a/src/language/utils/ASTPrinter.cpp b/src/language/utils/ASTPrinter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bf18bdcf88f6399283750dac9ab0b38d8bf0400 --- /dev/null +++ b/src/language/utils/ASTPrinter.cpp @@ -0,0 +1,98 @@ +#include <language/utils/ASTPrinter.hpp> + +#include <language/PEGGrammar.hpp> +#include <utils/EscapedString.hpp> + +void +ASTPrinter::_print(std::ostream& os, const ASTNode& node) const +{ + os << '(' << rang::fgB::yellow; + if (node.is_root()) { + os << "root"; + } else { + os << node.name(); + } + os << rang::fg::reset; + + if (node.is_type<language::name>() or node.is_type<language::literal>() or node.is_type<language::integer>() or + node.is_type<language::real>()) { + os << ':' << rang::fgB::green << node.string() << rang::fg::reset; + } + + if (m_info & static_cast<InfoBaseType>(Info::data_type)) { + os << ':'; + os << dataTypeName(node.m_data_type) << rang::fg::reset; + } + + if (m_info & static_cast<InfoBaseType>(Info::exec_type)) { + if (node.m_node_processor) { + os << ':'; + os << rang::fgB::magenta; + os << node.m_node_processor->typeIdName(); + os << rang::fg::reset; + } + } + + os << ")\n"; + + if (not node.children.empty()) { + _print(os, node.children); + } +} + +template <typename NodeVector> +void +ASTPrinter::_print(std::ostream& os, const NodeVector& node_list) const +{ + for (size_t i_child = 0; i_child < node_list.size(); ++i_child) { + if (i_child != node_list.size() - 1) { + os << rang::fgB::green << prefix << T_junction << rang::fg::reset; + } else { + os << rang::fgB::green << prefix << L_junction << rang::fg::reset; + } + auto& child = *(node_list[i_child]); + if (not child.children.empty()) { + last_prefix_size.push_back(prefix.size()); + if (i_child != node_list.size() - 1) { + prefix += pipe_space; + } else { + prefix += space_space; + } + + _print(os, *(node_list[i_child])); + + prefix.resize(last_prefix_size[last_prefix_size.size() - 1]); + last_prefix_size.pop_back(); + } else { + _print(os, *(node_list[i_child])); + } + } +} + +std::ostream& +operator<<(std::ostream& os, const ASTPrinter& ast_printer) +{ + ast_printer._print(os, ast_printer.m_node); + return os; +} + +ASTPrinter::ASTPrinter(const ASTNode& node, Format format, std::initializer_list<Info> initializer_list) : m_node{node} +{ + if (format == Format::pretty) { + T_junction = " \u251c\u2500\u2500"; + L_junction = " \u2514\u2500\u2500"; + pipe_space = " \u2502 "; + space_space = " "; + } else { + Assert(format == Format::raw); + T_junction = " +-"; + L_junction = " `-"; + pipe_space = " | "; + space_space = " "; + } + + m_info = 0; + for (auto i : initializer_list) { + m_info |= static_cast<InfoBaseType>(i); + } +} diff --git a/src/language/utils/ASTPrinter.hpp b/src/language/utils/ASTPrinter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..02838edf6ea38f03f212770cd48c01e51d9c9298 --- /dev/null +++ b/src/language/utils/ASTPrinter.hpp @@ -0,0 +1,58 @@ +#ifndef AST_PRINTER_HPP +#define AST_PRINTER_HPP + +#include <language/ast/ASTNode.hpp> + +class ASTPrinter +{ + public: + enum class Format + { + raw, + pretty + }; + + using InfoBaseType = uint32_t; + + enum class Info : InfoBaseType + { + none = 0, + data_type = 1 << 0, + exec_type = 1 << 1, + all = std::numeric_limits<InfoBaseType>::max() + }; + + private: + const ASTNode& m_node; + + InfoBaseType m_info; + + mutable std::string prefix; + mutable std::vector<int> last_prefix_size; + + std::string T_junction; + std::string L_junction; + + std::string pipe_space; + std::string space_space; + + void _print(std::ostream& os, const ASTNode& node) const; + + template <typename NodeVector> + void _print(std::ostream& os, const NodeVector& node_list) const; + + public: + friend std::ostream& operator<<(std::ostream& os, const ASTPrinter& ast_printer); + + ASTPrinter(const ASTNode& node, + Format format = Format::pretty, + std::initializer_list<Info> initializer_list = {Info::all}); + + ASTPrinter(const ASTPrinter&) = delete; + + ASTPrinter(ASTPrinter&&) = delete; + + ~ASTPrinter() = default; +}; + +#endif // AST_PRINTER_HPP diff --git a/src/language/utils/BuiltinFunctionEmbedder.hpp b/src/language/utils/BuiltinFunctionEmbedder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3974398e1803856585f91f09565b29da3d877533 --- /dev/null +++ b/src/language/utils/BuiltinFunctionEmbedder.hpp @@ -0,0 +1,316 @@ +#ifndef BUILTIN_FUNCTION_EMBEDDER_HPP +#define BUILTIN_FUNCTION_EMBEDDER_HPP + +#include <language/ast/ASTNodeDataType.hpp> +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/DataVariant.hpp> +#include <language/utils/FunctionTable.hpp> +#include <utils/Demangle.hpp> +#include <utils/Exceptions.hpp> +#include <utils/PugsTraits.hpp> + +#include <functional> +#include <memory> +#include <vector> + +class IBuiltinFunctionEmbedder +{ + public: + virtual size_t numberOfParameters() const = 0; + + virtual ASTNodeDataType getReturnDataType() const = 0; + + virtual std::vector<ASTNodeDataType> getParameterDataTypes() const = 0; + + virtual DataVariant apply(const std::vector<DataVariant>&) const = 0; + + IBuiltinFunctionEmbedder() = default; + + IBuiltinFunctionEmbedder(const IBuiltinFunctionEmbedder&) = delete; + IBuiltinFunctionEmbedder(IBuiltinFunctionEmbedder&&) = delete; + + virtual ~IBuiltinFunctionEmbedder() = default; +}; + +template <typename FX, typename... Args> +class BuiltinFunctionEmbedder +{ + static_assert(std::is_class_v<BuiltinFunctionEmbedder<FX, Args...>>, + "wrong template parameters do not use <FX, Args...>, use <FX(Args...)>"); +}; + +template <typename T> +inline constexpr bool is_const_ref_or_non_ref = (std::is_const_v<T> and std::is_lvalue_reference_v<T>) or + (not std::is_lvalue_reference_v<T>); + +template <typename FX, typename... Args> +class BuiltinFunctionEmbedder<FX(Args...)> : public IBuiltinFunctionEmbedder +{ + private: + std::function<FX(Args...)> m_f; + using ArgsTuple = std::tuple<std::decay_t<Args>...>; + + template <size_t I> + PUGS_INLINE void + _copyValue(ArgsTuple& t, const std::vector<DataVariant>& v) const + { + std::visit( + [&](auto&& v_i) { + using Ti_Type = std::decay_t<decltype(std::get<I>(t))>; + using Vi_Type = std::decay_t<decltype(v_i)>; + + if constexpr ((std::is_same_v<Vi_Type, Ti_Type>)) { + std::get<I>(t) = v_i; + } else if constexpr ((std::is_arithmetic_v<Vi_Type>)and(std::is_arithmetic_v<Ti_Type> or + std::is_same_v<Ti_Type, std::string>)) { + std::get<I>(t) = v_i; + } else if constexpr (is_shared_ptr_v<Ti_Type>) { + if constexpr (std::is_same_v<Vi_Type, EmbeddedData>) { + using Ti_handeled_type = typename Ti_Type::element_type; + try { + auto& data_handler = dynamic_cast<const DataHandler<Ti_handeled_type>&>(v_i.get()); + std::get<I>(t) = data_handler.data_ptr(); + } + catch (std::bad_cast&) { + throw UnexpectedError("unexpected argument types while casting: invalid EmbeddedData type, expecting " + + demangle<DataHandler<Ti_handeled_type>>()); + } + } else { + throw UnexpectedError("unexpected argument types while casting: expecting EmbeddedData"); + } + } else if constexpr (std::is_same_v<Vi_Type, std::vector<EmbeddedData>>) { + if constexpr (is_std_vector_v<Ti_Type>) { + using Ti_value_type = typename Ti_Type::value_type; + if constexpr (is_shared_ptr_v<Ti_value_type>) { + static_assert(is_shared_ptr_v<Ti_value_type>, "expecting shared_ptr"); + + using Ti_handeled_type = typename Ti_value_type::element_type; + std::get<I>(t).resize(v_i.size()); + for (size_t j = 0; j < v_i.size(); ++j) { + try { + auto& data_handler = dynamic_cast<const DataHandler<Ti_handeled_type>&>(v_i[j].get()); + std::get<I>(t)[j] = data_handler.data_ptr(); + } + catch (std::bad_cast&) { + throw UnexpectedError( + "unexpected argument types while casting: invalid EmbeddedData type, expecting " + + demangle<DataHandler<Ti_handeled_type>>()); + } + } + } else { + throw UnexpectedError("unexpected argument types while casting \"" + demangle<Vi_Type>() + "\" to \"" + + demangle<Ti_Type>() + '"'); + } + } else { + throw UnexpectedError("unexpected argument types while casting \"" + demangle<Vi_Type>() + "\" to \"" + + demangle<Ti_Type>() + '"'); + } + } else { + throw UnexpectedError("unexpected argument types while casting \"" + demangle<Vi_Type>() + "\" to \"" + + demangle<Ti_Type>() + '"'); + } + }, + v[I]); + } + + template <size_t... I> + PUGS_INLINE void + _copyFromVector(ArgsTuple& t, const std::vector<DataVariant>& v, std::index_sequence<I...>) const + { + Assert(sizeof...(Args) == v.size()); + (_copyValue<I>(t, v), ...); + } + + template <typename T> + PUGS_INLINE ASTNodeDataType + _getDataType() const + { + if constexpr (is_data_variant_v<T>) { + return ast_node_data_type_from<T>; + } else if constexpr (std::is_same_v<void, T>) { + return ASTNodeDataType::void_t; + } else { + Assert(ast_node_data_type_from<T> != ASTNodeDataType::undefined_t); + return ast_node_data_type_from<T>; + } + } + + template <size_t I> + PUGS_INLINE ASTNodeDataType + _getOneParameterDataType(ArgsTuple& t) const + { + using ArgN_T = std::decay_t<decltype(std::get<I>(t))>; + return _getDataType<ArgN_T>(); + } + + template <size_t... I> + PUGS_INLINE std::vector<ASTNodeDataType> + _getParameterDataTypes(ArgsTuple t, std::index_sequence<I...>) const + { + std::vector<ASTNodeDataType> parameter_type_list; + (parameter_type_list.push_back(this->_getOneParameterDataType<I>(t)), ...); + return parameter_type_list; + } + + template <typename T> + PUGS_INLINE std::shared_ptr<IDataHandler> + _createHandler(std::shared_ptr<T> data) const + { + return std::make_shared<DataHandler<T>>(data); + } + + template <size_t I> + PUGS_INLINE void constexpr _check_arg() const + { + using ArgN_T = std::tuple_element_t<I, std::tuple<Args...>>; + if constexpr (std::is_lvalue_reference_v<ArgN_T>) { + static_assert(std::is_const_v<std::remove_reference_t<ArgN_T>>, + "builtin function arguments are non mutable use 'const' when passing references"); + } + + if constexpr (is_std_ptr_v<ArgN_T>) { + static_assert(std::is_const_v<typename ArgN_T::element_type>, + "builtin function arguments are non mutable. For instance use std::shared_ptr<const T>"); + } + } + + template <size_t... I> + PUGS_INLINE void constexpr _check_arg_list(std::index_sequence<I...>) const + { + (_check_arg<I>(), ...); + } + + public: + PUGS_INLINE ASTNodeDataType + getReturnDataType() const final + { + return _getDataType<FX>(); + } + + PUGS_INLINE std::vector<ASTNodeDataType> + getParameterDataTypes() const final + { + constexpr size_t N = std::tuple_size_v<ArgsTuple>; + ArgsTuple t; + using IndexSequence = std::make_index_sequence<N>; + + return this->_getParameterDataTypes(t, IndexSequence{}); + } + + PUGS_INLINE size_t + numberOfParameters() const final + { + return sizeof...(Args); + } + + public: + PUGS_INLINE + DataVariant + apply(const std::vector<DataVariant>& x) const final + { + constexpr size_t N = std::tuple_size_v<ArgsTuple>; + ArgsTuple t; + using IndexSequence = std::make_index_sequence<N>; + + this->_copyFromVector(t, x, IndexSequence{}); + if constexpr (is_data_variant_v<FX>) { + return {std::apply(m_f, t)}; + } else if constexpr (std::is_same_v<FX, void>) { + std::apply(m_f, t); + return {}; + } else { + return EmbeddedData(_createHandler(std::apply(m_f, t))); + } + } + + BuiltinFunctionEmbedder(std::function<FX(Args...)> f) : m_f{f} + { + using IndexSequence = std::make_index_sequence<std::tuple_size_v<ArgsTuple>>; + this->_check_arg_list(IndexSequence{}); + + static_assert((std::is_same_v<Args, Args> and ...)); + } + + BuiltinFunctionEmbedder(const BuiltinFunctionEmbedder&) = delete; + BuiltinFunctionEmbedder(BuiltinFunctionEmbedder&&) = delete; + + ~BuiltinFunctionEmbedder() = default; +}; + +template <typename FX> +class BuiltinFunctionEmbedder<FX, void> +{ + static_assert(std::is_class_v<BuiltinFunctionEmbedder<FX, void>>, + "wrong template parameters do not use <FX, void>, use <FX(void)>"); +}; + +template <typename FX> +class BuiltinFunctionEmbedder<FX(void)> : public IBuiltinFunctionEmbedder +{ + private: + std::function<FX(void)> m_f; + + template <typename T> + PUGS_INLINE std::shared_ptr<IDataHandler> + _createHandler(std::shared_ptr<T> data) const + { + return std::make_shared<DataHandler<T>>(data); + } + + template <typename T> + PUGS_INLINE ASTNodeDataType + _getDataType() const + { + if constexpr (is_data_variant_v<T>) { + return ast_node_data_type_from<T>; + } else if constexpr (std::is_same_v<void, T>) { + return ASTNodeDataType::void_t; + } else { + Assert(ast_node_data_type_from<T> != ASTNodeDataType::undefined_t); + return ast_node_data_type_from<T>; + } + } + + public: + PUGS_INLINE ASTNodeDataType + getReturnDataType() const final + { + return this->_getDataType<FX>(); + } + + PUGS_INLINE std::vector<ASTNodeDataType> + getParameterDataTypes() const final + { + return {}; + } + + PUGS_INLINE size_t + numberOfParameters() const final + { + return 0; + } + + PUGS_INLINE + DataVariant + apply(const std::vector<DataVariant>&) const final + { + if constexpr (is_data_variant_v<FX>) { + return {m_f()}; + } else if constexpr (std::is_same_v<FX, void>) { + m_f(); + return {}; + } else { + return EmbeddedData(_createHandler(m_f())); + } + } + + BuiltinFunctionEmbedder(std::function<FX(void)> f) : m_f{f} {} + + BuiltinFunctionEmbedder(const BuiltinFunctionEmbedder&) = delete; + BuiltinFunctionEmbedder(BuiltinFunctionEmbedder&&) = delete; + + ~BuiltinFunctionEmbedder() = default; +}; + +#endif // BUILTIN_FUNCTION_EMBEDDER_HPP diff --git a/src/language/utils/CMakeLists.txt b/src/language/utils/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a8216a9ca62a440c7eb84111cbb87d26ae6b1d3 --- /dev/null +++ b/src/language/utils/CMakeLists.txt @@ -0,0 +1,14 @@ +# ------------------- Source files -------------------- + +add_library(PugsLanguageUtils + ASTDotPrinter.cpp + ASTPrinter.cpp + DataVariant.cpp + EmbeddedData.cpp + ) + + + +add_dependencies(PugsLanguageModules + PugsUtils + PugsMesh) diff --git a/src/language/utils/DataHandler.hpp b/src/language/utils/DataHandler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c09256e2a8379cbc934394304fd35d1f98610348 --- /dev/null +++ b/src/language/utils/DataHandler.hpp @@ -0,0 +1,36 @@ +#ifndef DATA_HANDLER_HPP +#define DATA_HANDLER_HPP + +#include <utils/PugsAssert.hpp> + +#include <memory> + +class IDataHandler +{ + public: + IDataHandler(const IDataHandler&) = delete; + IDataHandler(IDataHandler&&) = delete; + + IDataHandler() = default; + + virtual ~IDataHandler() = default; +}; + +template <typename DataT> +class DataHandler : public IDataHandler +{ + private: + std::shared_ptr<DataT> m_data; + + public: + std::shared_ptr<DataT> + data_ptr() const + { + return m_data; + } + + DataHandler(std::shared_ptr<DataT> data) : m_data(data) {} + ~DataHandler() = default; +}; + +#endif // DATA_HANDLER_HPP diff --git a/src/language/utils/DataVariant.cpp b/src/language/utils/DataVariant.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc82eec7b805cd49daa2a097490b36fa33e0c561 --- /dev/null +++ b/src/language/utils/DataVariant.cpp @@ -0,0 +1,45 @@ +#include <language/utils/DataVariant.hpp> + +#include <utils/PugsAssert.hpp> +#include <utils/PugsTraits.hpp> + +std::ostream& +operator<<(std::ostream& os, const DataVariant& v) +{ + std::visit( + [&](auto&& v) { + using ValueT = std::decay_t<decltype(v)>; + if constexpr (std::is_same_v<ValueT, std::monostate>) { + os << "--"; + } else if constexpr (is_std_vector_v<ValueT>) { + os << '('; + if (v.size() > 0) { + os << v[0]; + } + for (size_t i = 1; i < v.size(); ++i) { + os << ", " << v[i]; + } + os << ')'; + } else if constexpr (std::is_same_v<bool, ValueT>) { + os << std::boolalpha << v; + } else { + os << v; + } + }, + v); + + return os; +} + +std::ostream& +operator<<(std::ostream& os, const AggregateDataVariant& compound) +{ + Assert(compound.m_data_vector.size() > 0, "unexpected compound data size"); + os << '('; + os << compound.m_data_vector[0]; + for (size_t i = 1; i < compound.m_data_vector.size(); ++i) { + os << ", " << compound.m_data_vector[i]; + } + os << ')'; + return os; +} diff --git a/src/language/utils/DataVariant.hpp b/src/language/utils/DataVariant.hpp new file mode 100644 index 0000000000000000000000000000000000000000..13744172a73c2e3c54d97412cd654ae7211ad42c --- /dev/null +++ b/src/language/utils/DataVariant.hpp @@ -0,0 +1,98 @@ +#ifndef DATA_VARIANT_HPP +#define DATA_VARIANT_HPP + +#include <algebra/TinyVector.hpp> +#include <language/utils/EmbeddedData.hpp> +#include <language/utils/FunctionSymbolId.hpp> +#include <utils/PugsTraits.hpp> + +#include <iostream> +#include <tuple> +#include <variant> +#include <vector> + +class AggregateDataVariant; + +using DataVariant = std::variant<std::monostate, + bool, + uint64_t, + int64_t, + double, + std::string, + TinyVector<1>, + TinyVector<2>, + TinyVector<3>, + EmbeddedData, + std::vector<bool>, + std::vector<uint64_t>, + std::vector<int64_t>, + std::vector<double>, + std::vector<std::string>, + std::vector<TinyVector<1>>, + std::vector<TinyVector<2>>, + std::vector<TinyVector<3>>, + std::vector<EmbeddedData>, + AggregateDataVariant, + FunctionSymbolId>; + +template <typename T, typename...> +inline constexpr bool is_data_variant_v = is_variant<T, DataVariant>::value; + +std::ostream& operator<<(std::ostream& os, const DataVariant& v); + +class AggregateDataVariant // LCOV_EXCL_LINE +{ + private: + std::vector<DataVariant> m_data_vector; + bool m_is_flattenable = true; + + public: + friend std::ostream& operator<<(std::ostream& os, const AggregateDataVariant& compound); + + PUGS_INLINE + void + setIsFlattenable(bool is_flattenable) + { + m_is_flattenable = is_flattenable; + } + + PUGS_INLINE + bool + isFlattenable() const + { + return m_is_flattenable; + } + + PUGS_INLINE + size_t + size() const + { + return m_data_vector.size(); + } + + PUGS_INLINE + DataVariant& operator[](size_t i) + { + Assert(i < m_data_vector.size()); + return m_data_vector[i]; + } + + PUGS_INLINE + const DataVariant& operator[](size_t i) const + { + Assert(i < m_data_vector.size()); + return m_data_vector[i]; + } + + AggregateDataVariant& operator=(const AggregateDataVariant&) = default; + AggregateDataVariant& operator=(AggregateDataVariant&&) = default; + + AggregateDataVariant(std::vector<DataVariant>&& data_vector) : m_data_vector{data_vector} {} + + AggregateDataVariant(const AggregateDataVariant&) = default; + AggregateDataVariant(AggregateDataVariant&&) = default; + + AggregateDataVariant() = default; +}; + +#endif // DATA_VARIANT_HPP diff --git a/src/language/utils/EmbeddedData.cpp b/src/language/utils/EmbeddedData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23ab3c2789e8b3995e6a475999dbb005184fd160 --- /dev/null +++ b/src/language/utils/EmbeddedData.cpp @@ -0,0 +1,14 @@ +#include <language/utils/EmbeddedData.hpp> + +#include <language/utils/DataHandler.hpp> + +std::ostream& +operator<<(std::ostream& os, const EmbeddedData&) +{ + os << "embedded_data"; + return os; +} + +EmbeddedData::EmbeddedData() {} + +EmbeddedData::~EmbeddedData() {} diff --git a/src/language/utils/EmbeddedData.hpp b/src/language/utils/EmbeddedData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..14a591e60751b5ca8a76b440e6ac379fe5040233 --- /dev/null +++ b/src/language/utils/EmbeddedData.hpp @@ -0,0 +1,39 @@ +#ifndef EMBEDDED_DATA_HPP +#define EMBEDDED_DATA_HPP + +#include <utils/PugsAssert.hpp> + +#include <iostream> +#include <memory> + +class IDataHandler; + +class EmbeddedData +{ + private: + std::shared_ptr<IDataHandler> m_data_handler{nullptr}; + + public: + [[nodiscard]] const IDataHandler& + get() const + { + Assert(m_data_handler); + return *m_data_handler; + } + + friend std::ostream& operator<<(std::ostream& os, const EmbeddedData&); + + EmbeddedData& operator=(const EmbeddedData&) = default; + EmbeddedData& operator=(EmbeddedData&&) = default; + + EmbeddedData(const EmbeddedData&) = default; + EmbeddedData(EmbeddedData&&) = default; + + EmbeddedData(const std::shared_ptr<IDataHandler>& data_handler) : m_data_handler{data_handler} {} + EmbeddedData(std::shared_ptr<IDataHandler>&& data_handler) : m_data_handler{std::move(data_handler)} {} + + EmbeddedData(); + ~EmbeddedData(); +}; + +#endif // EMBEDDED_DATA_HPP diff --git a/src/language/utils/EmbedderTable.hpp b/src/language/utils/EmbedderTable.hpp new file mode 100644 index 0000000000000000000000000000000000000000..60441cec257aee69afc0caa72faf9a487fc736d0 --- /dev/null +++ b/src/language/utils/EmbedderTable.hpp @@ -0,0 +1,40 @@ +#ifndef EMBEDDER_TABLE_HPP +#define EMBEDDER_TABLE_HPP + +#include <utils/PugsAssert.hpp> + +#include <memory> +#include <vector> + +template <typename EmbedderT> +class EmbedderTable +{ + private: + std::vector<std::shared_ptr<EmbedderT>> m_embedder_list; + + public: + PUGS_INLINE + size_t + size() const + { + return m_embedder_list.size(); + } + + PUGS_INLINE + const std::shared_ptr<EmbedderT>& operator[](size_t embedder_id) const + { + Assert(embedder_id < m_embedder_list.size()); + return m_embedder_list[embedder_id]; + } + + void + add(std::shared_ptr<EmbedderT> embedder) + { + m_embedder_list.push_back(embedder); + } + + EmbedderTable() = default; + ~EmbedderTable() = default; +}; + +#endif // EMBEDDER_TABLE_HPP diff --git a/src/language/utils/FunctionSymbolId.hpp b/src/language/utils/FunctionSymbolId.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f96b783fa5bf3853507f4c650e02972faa5d6ebb --- /dev/null +++ b/src/language/utils/FunctionSymbolId.hpp @@ -0,0 +1,54 @@ +#ifndef FUNCTION_SYMBOL_ID_HPP +#define FUNCTION_SYMBOL_ID_HPP + +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +#include <cstddef> +#include <iostream> +#include <memory> + +class SymbolTable; +class FunctionSymbolId +{ + private: + uint64_t m_function_id; + std::shared_ptr<SymbolTable> m_symbol_table = nullptr; + + public: + [[nodiscard]] PUGS_INLINE uint64_t + id() const noexcept + { + return m_function_id; + } + + [[nodiscard]] PUGS_INLINE const SymbolTable& + symbolTable() const + { + Assert(m_symbol_table, "FunctionSymbolId is not initialized properly"); + return *m_symbol_table; + } + + friend std::ostream& + operator<<(std::ostream& os, const FunctionSymbolId& function_symbol_id) + { + os << function_symbol_id.m_function_id; + return os; + } + + FunctionSymbolId& operator=(const FunctionSymbolId&) = default; + FunctionSymbolId& operator=(FunctionSymbolId&&) = default; + + FunctionSymbolId() = default; + + FunctionSymbolId(const FunctionSymbolId&) = default; + FunctionSymbolId(FunctionSymbolId&&) = default; + + FunctionSymbolId(uint64_t function_id, const std::shared_ptr<SymbolTable>& symbol_table) + : m_function_id(function_id), m_symbol_table(symbol_table) + {} + + ~FunctionSymbolId() = default; +}; + +#endif // FUNCTION_SYMBOL_ID_HPP diff --git a/src/language/utils/FunctionTable.hpp b/src/language/utils/FunctionTable.hpp new file mode 100644 index 0000000000000000000000000000000000000000..43232fd60e4482a73dca1a4b257c7a6c0b6ef28a --- /dev/null +++ b/src/language/utils/FunctionTable.hpp @@ -0,0 +1,90 @@ +#ifndef FUNCTION_TABLE_HPP +#define FUNCTION_TABLE_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeDataType.hpp> +#include <language/utils/DataVariant.hpp> +#include <utils/PugsAssert.hpp> + +#include <pegtl/position.hpp> + +class FunctionDescriptor +{ + std::string m_name; + + std::unique_ptr<ASTNode> m_domain_mapping_node; + std::unique_ptr<ASTNode> m_definition_node; + + public: + const std::string& + name() const + { + return m_name; + } + + auto& + domainMappingNode() const + { + Assert(m_domain_mapping_node, "undefined domain mapping node"); + return *m_domain_mapping_node; + } + + auto& + definitionNode() const + { + Assert(m_definition_node, "undefined expression node"); + return *m_definition_node; + } + + FunctionDescriptor& operator=(FunctionDescriptor&&) = default; + + FunctionDescriptor(const std::string& name, + std::unique_ptr<ASTNode>&& domain_mapping_node, + std::unique_ptr<ASTNode>&& definition_node) + : m_name{name}, m_domain_mapping_node(std::move(domain_mapping_node)), m_definition_node(std::move(definition_node)) + {} + + FunctionDescriptor(FunctionDescriptor&&) = default; + FunctionDescriptor() = default; + ~FunctionDescriptor() = default; +}; + +class FunctionTable +{ + private: + std::vector<FunctionDescriptor> m_function_descriptor_list; + + public: + PUGS_INLINE + size_t + size() const + { + return m_function_descriptor_list.size(); + } + + PUGS_INLINE + FunctionDescriptor& operator[](size_t function_id) + { + Assert(function_id < m_function_descriptor_list.size()); + return m_function_descriptor_list[function_id]; + } + + PUGS_INLINE + const FunctionDescriptor& operator[](size_t function_id) const + { + Assert(function_id < m_function_descriptor_list.size()); + return m_function_descriptor_list[function_id]; + } + + size_t + add(FunctionDescriptor&& function_descriptor) + { + m_function_descriptor_list.emplace_back(std::move(function_descriptor)); + return m_function_descriptor_list.size() - 1; + } + + FunctionTable() = default; + ~FunctionTable() = default; +}; + +#endif // FUNCTION_TABLE_HPP diff --git a/src/language/utils/PugsFunctionAdapter.hpp b/src/language/utils/PugsFunctionAdapter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..660cae99e206b3320a9d28861fbc2ee0236d6022 --- /dev/null +++ b/src/language/utils/PugsFunctionAdapter.hpp @@ -0,0 +1,284 @@ +#ifndef PUGS_FUNCTION_ADAPTER_HPP +#define PUGS_FUNCTION_ADAPTER_HPP + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeDataType.hpp> +#include <language/node_processor/ExecutionPolicy.hpp> +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/Array.hpp> +#include <utils/Exceptions.hpp> +#include <utils/PugsMacros.hpp> + +#include <Kokkos_Core.hpp> + +#include <array> + +template <typename T> +class PugsFunctionAdapter; +template <typename OutputType, typename... InputType> +class PugsFunctionAdapter<OutputType(InputType...)> +{ + protected: + using InputTuple = std::tuple<std::decay_t<InputType>...>; + constexpr static size_t NArgs = std::tuple_size_v<InputTuple>; + + private: + template <typename T, typename... Args> + PUGS_INLINE static void + _convertArgs(ExecutionPolicy::Context& context, size_t i_context, const T& t, Args&&... args) + { + context[i_context++] = t; + if constexpr (sizeof...(Args) > 0) { + _convertArgs(context, i_context, std::forward<Args>(args)...); + } + } + + template <size_t I> + [[nodiscard]] PUGS_INLINE static bool + _checkValidArgumentDataType(const ASTNode& arg_expression) noexcept + { + using Arg = std::tuple_element_t<I, InputTuple>; + + constexpr const ASTNodeDataType& expected_input_data_type = ast_node_data_type_from<Arg>; + const ASTNodeDataType& arg_data_type = arg_expression.m_data_type; + + return isNaturalConversion(expected_input_data_type, arg_data_type); + } + + template <size_t... I> + [[nodiscard]] PUGS_INLINE static bool + _checkAllInputDataType(const ASTNode& input_expression, std::index_sequence<I...>) + { + Assert(NArgs == input_expression.children.size()); + return (_checkValidArgumentDataType<I>(*input_expression.children[I]) and ...); + } + + [[nodiscard]] PUGS_INLINE static bool + _checkValidInputDataType(const ASTNode& input_expression) noexcept + { + if constexpr (NArgs == 1) { + return _checkValidArgumentDataType<0>(input_expression); + } else { + if (input_expression.children.size() != NArgs) { + return false; + } + + using IndexSequence = std::make_index_sequence<NArgs>; + return _checkAllInputDataType(input_expression, IndexSequence{}); + } + } + + [[nodiscard]] PUGS_INLINE static bool + _checkValidOutputDataType(const ASTNode& return_expression) noexcept + { + constexpr const ASTNodeDataType& expected_return_data_type = ast_node_data_type_from<OutputType>; + const ASTNodeDataType& return_data_type = return_expression.m_data_type; + + if (not isNaturalConversion(return_data_type, expected_return_data_type)) { + if (expected_return_data_type == ASTNodeDataType::vector_t) { + if (return_data_type == ASTNodeDataType::list_t) { + if (expected_return_data_type.dimension() != return_expression.children.size()) { + return false; + } else { + for (const auto& child : return_expression.children) { + const ASTNodeDataType& data_type = child->m_data_type; + if (not isNaturalConversion(data_type, ast_node_data_type_from<double>)) { + return false; + } + } + } + } else if ((expected_return_data_type.dimension() == 1) and + isNaturalConversion(return_data_type, ast_node_data_type_from<double>)) { + return true; + } else if (return_data_type == ast_node_data_type_from<int64_t>) { + // 0 is the only valid value for vectors + return (return_expression.string() == "0"); + } else { + return false; + } + } else { + return false; + } + } + return true; + } + + template <typename Arg, typename... RemainingArgs> + [[nodiscard]] PUGS_INLINE static std::string + _getCompoundTypeName() + { + if constexpr (sizeof...(RemainingArgs) > 0) { + return dataTypeName(ast_node_data_type_from<Arg>) + '*' + _getCompoundTypeName<RemainingArgs...>(); + } else { + return dataTypeName(ast_node_data_type_from<Arg>); + } + } + + [[nodiscard]] static std::string + _getInputDataTypeName() + { + return _getCompoundTypeName<InputType...>(); + } + + PUGS_INLINE static void + _checkFunction(const FunctionDescriptor& function) + { + bool has_valid_input = _checkValidInputDataType(*function.definitionNode().children[0]); + bool has_valid_output = _checkValidOutputDataType(*function.definitionNode().children[1]); + + if (not(has_valid_input and has_valid_output)) { + std::ostringstream error_message; + error_message << "invalid function type" << rang::style::reset << "\nnote: expecting " << rang::fgB::yellow + << _getInputDataTypeName() << " -> " << dataTypeName(ast_node_data_type_from<OutputType>) + << rang::style::reset << '\n' + << "note: provided function " << rang::fgB::magenta << function.name() << ": " + << function.domainMappingNode().string() << rang::style::reset << std::ends; + throw NormalError(error_message.str()); + } + } + + protected: + [[nodiscard]] PUGS_INLINE static auto& + getFunctionExpression(const FunctionSymbolId& function_symbol_id) + { + auto& function = function_symbol_id.symbolTable().functionTable()[function_symbol_id.id()]; + _checkFunction(function); + + return *function.definitionNode().children[1]; + } + + [[nodiscard]] PUGS_INLINE static auto + getContextList(const ASTNode& expression) + { + Array<ExecutionPolicy> context_list(Kokkos::DefaultExecutionSpace::impl_thread_pool_size()); + auto& context = expression.m_symbol_table->context(); + + for (size_t i = 0; i < context_list.size(); ++i) { + context_list[i] = + ExecutionPolicy(ExecutionPolicy{}, + {context.id(), std::make_shared<ExecutionPolicy::Context::Values>(context.size())}); + } + + return context_list; + } + + template <typename... Args> + PUGS_INLINE static void + convertArgs(ExecutionPolicy::Context& context, Args&&... args) + { + static_assert(std::is_same_v<std::tuple<std::decay_t<InputType>...>, std::tuple<std::decay_t<Args>...>>, + "unexpected input type"); + _convertArgs(context, 0, args...); + } + + [[nodiscard]] PUGS_INLINE static std::function<OutputType(DataVariant&& result)> + getResultConverter(const ASTNodeDataType& data_type) + { + if constexpr (is_tiny_vector_v<OutputType>) { + switch (data_type) { + case ASTNodeDataType::list_t: { + return [](DataVariant&& result) -> OutputType { + AggregateDataVariant& v = std::get<AggregateDataVariant>(result); + OutputType x; + + for (size_t i = 0; i < x.dimension(); ++i) { + std::visit( + [&](auto&& vi) { + using Vi_T = std::decay_t<decltype(vi)>; + if constexpr (std::is_arithmetic_v<Vi_T>) { + x[i] = vi; + } else { + // LCOV_EXCL_START + throw UnexpectedError("expecting arithmetic value"); + // LCOV_EXCL_STOP + } + }, + v[i]); + } + return x; + }; + } + case ASTNodeDataType::vector_t: { + return [](DataVariant&& result) -> OutputType { return std::get<OutputType>(result); }; + } + case ASTNodeDataType::bool_t: { + if constexpr (std::is_same_v<OutputType, TinyVector<1>>) { + return + [](DataVariant&& result) -> OutputType { return OutputType{static_cast<double>(std::get<bool>(result))}; }; + } else { + // LCOV_EXCL_START + throw UnexpectedError("unexpected data_type, cannot convert \"" + dataTypeName(data_type) + "\" to \"" + + dataTypeName(ast_node_data_type_from<OutputType>) + "\""); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::unsigned_int_t: { + if constexpr (std::is_same_v<OutputType, TinyVector<1>>) { + return [](DataVariant&& result) -> OutputType { + return OutputType(static_cast<double>(std::get<uint64_t>(result))); + }; + } else { + // LCOV_EXCL_START + throw UnexpectedError("unexpected data_type, cannot convert \"" + dataTypeName(data_type) + "\" to \"" + + dataTypeName(ast_node_data_type_from<OutputType>) + "\""); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::int_t: { + if constexpr (std::is_same_v<OutputType, TinyVector<1>>) { + return [](DataVariant&& result) -> OutputType { + return OutputType{static_cast<double>(std::get<int64_t>(result))}; + }; + } else { + // If this point is reached must be a 0 vector + return [](DataVariant &&) -> OutputType { return OutputType{ZeroType{}}; }; + } + } + case ASTNodeDataType::double_t: { + if constexpr (std::is_same_v<OutputType, TinyVector<1>>) { + return [](DataVariant&& result) -> OutputType { return OutputType{std::get<double>(result)}; }; + } else { + // LCOV_EXCL_START + throw UnexpectedError("unexpected data_type, cannot convert \"" + dataTypeName(data_type) + "\" to \"" + + dataTypeName(ast_node_data_type_from<OutputType>) + "\""); + // LCOV_EXCL_STOP + } + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("unexpected data_type, cannot convert \"" + dataTypeName(data_type) + "\" to \"" + + dataTypeName(ast_node_data_type_from<OutputType>) + "\""); + } + // LCOV_EXCL_STOP + } + } else if constexpr (std::is_arithmetic_v<OutputType>) { + switch (data_type) { + case ASTNodeDataType::bool_t: { + return [](DataVariant&& result) -> OutputType { return std::get<bool>(result); }; + } + case ASTNodeDataType::unsigned_int_t: { + return [](DataVariant&& result) -> OutputType { return std::get<uint64_t>(result); }; + } + case ASTNodeDataType::int_t: { + return [](DataVariant&& result) -> OutputType { return std::get<int64_t>(result); }; + } + case ASTNodeDataType::double_t: { + return [](DataVariant&& result) -> OutputType { return std::get<double>(result); }; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("unexpected data_type, cannot convert \"" + dataTypeName(data_type) + "\" to \"" + + dataTypeName(ast_node_data_type_from<OutputType>) + "\""); + } + // LCOV_EXCL_STOP + } + } else { + static_assert(std::is_arithmetic_v<OutputType>, "unexpected output type"); + } + } + + PugsFunctionAdapter() = delete; +}; + +#endif // PUGS_FUNCTION_ADAPTER_HPP diff --git a/src/language/utils/SymbolTable.hpp b/src/language/utils/SymbolTable.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3eba77ec9c495a50183acda709abf030cbfc522b --- /dev/null +++ b/src/language/utils/SymbolTable.hpp @@ -0,0 +1,344 @@ +#ifndef SYMBOL_TABLE_HPP +#define SYMBOL_TABLE_HPP + +#include <language/ast/ASTNodeDataType.hpp> +#include <language/utils/DataVariant.hpp> +#include <language/utils/EmbedderTable.hpp> +#include <language/utils/FunctionTable.hpp> +#include <utils/PugsMacros.hpp> + +#include <pegtl/position.hpp> + +#include <iostream> + +class TypeDescriptor; +class IBuiltinFunctionEmbedder; + +class SymbolTable +{ + public: + class Attributes + { + private: + TAO_PEGTL_NAMESPACE::position m_position; + int32_t m_context_id; + + bool m_is_initialized{false}; + + ASTNodeDataType m_data_type{ASTNodeDataType::undefined_t}; + DataVariant m_value; + + public: + bool + hasLocalContext() const + { + return m_context_id != -1; + } + + const int32_t& + contextId() const + { + return m_context_id; + } + + auto& + value() + { + return m_value; + } + + const auto& + value() const + { + return m_value; + } + + const bool& + isInitialized() const + { + return m_is_initialized; + } + + void + setIsInitialized() + { + m_is_initialized = true; + } + + const ASTNodeDataType& + dataType() const + { + return m_data_type; + } + + auto + position() const + { + return m_position; + } + + void + setDataType(const ASTNodeDataType& data_type) + { + Assert(m_data_type == ASTNodeDataType::undefined_t, "data type has already been defined!"); + m_data_type = data_type; + } + + friend std::ostream& + operator<<(std::ostream& os, const Attributes& attributes) + { + os << rang::fg::green; + if (attributes.m_data_type == ASTNodeDataType::function_t) { + os << "function_id"; + } else { + os << dataTypeName(attributes.dataType()); + } + os << rang::style::reset << ':' << attributes.m_value; + + return os; + } + + Attributes(const TAO_PEGTL_NAMESPACE::position& position, int32_t context_id) + : m_position{position}, m_context_id{context_id} + {} + + Attributes(const Attributes&) = default; + }; + + class Symbol // LCOV_EXCL_LINE + { + private: + std::string m_name; + Attributes m_attributes; + + public: + PUGS_INLINE + const std::string& + name() const + { + return m_name; + } + + PUGS_INLINE + const Attributes& + attributes() const + { + return m_attributes; + } + + PUGS_INLINE + Attributes& + attributes() + { + return m_attributes; + } + + Symbol(const std::string& name, const Attributes& attributes) : m_name(name), m_attributes(attributes) {} + + Symbol& operator=(Symbol&&) = default; + Symbol& operator=(const Symbol&) = default; + + Symbol(const Symbol&) = default; + Symbol(Symbol&&) = default; + ~Symbol() = default; + }; + + class Context + { + private: + inline static int32_t next_context_id{0}; + + int32_t m_id; + size_t m_size{0}; + + public: + PUGS_INLINE + int32_t + id() const + { + return m_id; + } + + PUGS_INLINE + size_t + size() const + { + return m_size; + } + + PUGS_INLINE + size_t + getNextSymbolId() + { + return m_size++; + } + + Context() : m_id{next_context_id++} {} + + Context& operator=(const Context&) = default; // clazy:exclude=function-args-by-value + Context& operator=(Context&&) = default; + + Context(const Context&) = default; + Context(Context&&) = default; + ~Context() = default; + }; + + private: + std::vector<Symbol> m_symbol_list; + + std::shared_ptr<SymbolTable> m_parent_table; + std::shared_ptr<Context> m_context; + + std::shared_ptr<FunctionTable> m_function_table; + + std::shared_ptr<EmbedderTable<IBuiltinFunctionEmbedder>> m_builtin_function_embedder_table; + std::shared_ptr<EmbedderTable<TypeDescriptor>> m_type_embedder_table; + + public: + bool + hasContext() const + { + return bool{m_context}; + } + + const Context& + context() const + { + Assert(m_context); + return *m_context; + } + + const FunctionTable& + functionTable() const + { + Assert(m_function_table); + return *m_function_table; + } + + FunctionTable& + functionTable() + { + Assert(m_function_table); + return *m_function_table; + } + + const auto& + builtinFunctionEmbedderTable() const + { + Assert(m_builtin_function_embedder_table); + return *m_builtin_function_embedder_table; + } + + auto& + builtinFunctionEmbedderTable() + { + Assert(m_builtin_function_embedder_table); + return *m_builtin_function_embedder_table; + } + + auto& + typeEmbedderTable() + { + Assert(m_type_embedder_table); + return *m_type_embedder_table; + } + + const auto& + typeEmbedderTable() const + { + Assert(m_type_embedder_table); + return *m_type_embedder_table; + } + + friend std::ostream& + operator<<(std::ostream& os, const SymbolTable& symbol_table) + { + os << "-- Symbol table state -- parent : " << symbol_table.m_parent_table.get() << "\n"; + for (auto i_symbol : symbol_table.m_symbol_list) { + if (i_symbol.attributes().dataType() != ASTNodeDataType::builtin_function_t) { + os << ' ' << i_symbol.name() << ": " << std::boolalpha << i_symbol.attributes() << '\n'; + } + } + os << "------------------------\n"; + return os; + } + + void + clearValues() + { + for (auto& symbol : m_symbol_list) { + symbol.attributes().value() = DataVariant{}; + } + } + + auto + find(const std::string& symbol, const TAO_PEGTL_NAMESPACE::position& use_position) + { + auto i_symbol = m_symbol_list.end(); + + for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { + if (i_stored_symbol->name() == symbol) { + i_symbol = i_stored_symbol; + break; + } + } + + if (i_symbol != m_symbol_list.end() and (use_position.byte >= i_symbol->attributes().position().byte)) { + return std::make_pair(i_symbol, true); + } else { + if (m_parent_table) { + return m_parent_table->find(symbol, use_position); + } else { + return std::make_pair(i_symbol, false); + } + } + } + + auto + add(const std::string& symbol_name, const TAO_PEGTL_NAMESPACE::position& symbol_position) + { + for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { + if (i_stored_symbol->name() == symbol_name) { + return std::make_pair(i_stored_symbol, false); + } + } + + int32_t context_id = this->hasContext() ? m_context->id() : -1; + + auto i_symbol = + m_symbol_list.emplace(m_symbol_list.end(), Symbol{symbol_name, Attributes{symbol_position, context_id}}); + + if (this->hasContext()) { + i_symbol->attributes().value() = m_context->getNextSymbolId(); + } + + return std::make_pair(i_symbol, true); + } + + SymbolTable(const std::shared_ptr<SymbolTable>& parent_table, const std::shared_ptr<Context>& context) + : m_parent_table{parent_table}, + m_context{context}, + m_function_table{parent_table->m_function_table}, + m_builtin_function_embedder_table{parent_table->m_builtin_function_embedder_table}, + m_type_embedder_table{parent_table->m_type_embedder_table} + { + ; + } + + SymbolTable(const std::shared_ptr<SymbolTable>& parent_table) : SymbolTable{parent_table, parent_table->m_context} + { + ; + } + + SymbolTable() + : m_parent_table{nullptr}, + m_context{nullptr}, + m_function_table{std::make_shared<FunctionTable>()}, + m_builtin_function_embedder_table{std::make_shared<EmbedderTable<IBuiltinFunctionEmbedder>>()}, + m_type_embedder_table{std::make_shared<EmbedderTable<TypeDescriptor>>()} + { + ; + } +}; + +#endif // SYMBOL_TABLE_HPP diff --git a/src/language/utils/TypeDescriptor.hpp b/src/language/utils/TypeDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9da24e0d42096b93998867923ac26196bd694eb4 --- /dev/null +++ b/src/language/utils/TypeDescriptor.hpp @@ -0,0 +1,22 @@ +#ifndef TYPE_DESCRIPTOR_HPP +#define TYPE_DESCRIPTOR_HPP + +#include <string> + +class TypeDescriptor +{ + private: + std::string m_name; + + public: + const std::string& + name() const + { + return m_name; + } + + TypeDescriptor(std::string_view name) : m_name(name) {} + ~TypeDescriptor() = default; +}; + +#endif // TYPE_DESCRIPTOR_HPP diff --git a/src/main.cpp b/src/main.cpp index cd88b7ae1d949952da3bfa9ff5aeec07bb8d48eb..daf0d4edb97c9939c5b25217649452207a54816f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,11 @@ #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> -#include <scheme/BoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> +#include <scheme/NamedBoundaryDescriptor.hpp> +#include <scheme/NumberedBoundaryDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> #include <mesh/MeshNodeBoundary.hpp> @@ -35,392 +39,386 @@ int main(int argc, char* argv[]) { - try { - std::string filename = initialize(argc, argv); + std::string filename = initialize(argc, argv); - std::regex gmsh_regex("(.*).msh"); - if (not std::regex_match(filename, gmsh_regex)) { - parser(filename); - return 0; - } + std::regex gmsh_regex("(.*).msh"); + if (not std::regex_match(filename, gmsh_regex)) { + SynchronizerManager::create(); + MeshDataManager::create(); + parser(filename); + MeshDataManager::destroy(); + SynchronizerManager::destroy(); + finalize(); + return 0; + } - std::map<std::string, double> method_cost_map; + std::map<std::string, double> method_cost_map; - SynchronizerManager::create(); + MeshDataManager::create(); + SynchronizerManager::create(); - if (filename != "") { - std::cout << "Reading (gmsh) " << rang::style::underline << filename << rang::style::reset << " ...\n"; - Timer gmsh_timer; - gmsh_timer.reset(); - GmshReader gmsh_reader(filename); - method_cost_map["Mesh building"] = gmsh_timer.seconds(); - - std::shared_ptr<IMesh> p_mesh = gmsh_reader.mesh(); - - switch (p_mesh->dimension()) { - case 1: { - std::vector<std::string> sym_boundary_name_list = {"XMIN", "XMAX"}; - std::vector<std::shared_ptr<BoundaryConditionDescriptor>> bc_descriptor_list; - for (const auto& sym_boundary_name : sym_boundary_name_list) { - std::shared_ptr<BoundaryDescriptor> boudary_descriptor = - std::shared_ptr<BoundaryDescriptor>(new NamedBoundaryDescriptor(sym_boundary_name)); - SymmetryBoundaryConditionDescriptor* sym_bc_descriptor = - new SymmetryBoundaryConditionDescriptor(boudary_descriptor); - - bc_descriptor_list.push_back(std::shared_ptr<BoundaryConditionDescriptor>(sym_bc_descriptor)); - } + if (filename != "") { + std::cout << "Reading (gmsh) " << rang::style::underline << filename << rang::style::reset << " ...\n"; + Timer gmsh_timer; + gmsh_timer.reset(); + GmshReader gmsh_reader(filename); + method_cost_map["Mesh building"] = gmsh_timer.seconds(); + + std::shared_ptr<const IMesh> p_mesh = gmsh_reader.mesh(); - using ConnectivityType = Connectivity1D; - using MeshType = Mesh<ConnectivityType>; - using MeshDataType = MeshData<MeshType>; - using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; - - const MeshType& mesh = dynamic_cast<const MeshType&>(*gmsh_reader.mesh()); - - Timer timer; - timer.reset(); - MeshDataType mesh_data(mesh); - - std::vector<BoundaryConditionHandler> bc_list; - { - for (const auto& bc_descriptor : bc_descriptor_list) { - switch (bc_descriptor->type()) { - case BoundaryConditionDescriptor::Type::symmetry: { - const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = - dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); - for (size_t i_ref_node_list = 0; - i_ref_node_list < mesh.connectivity().numberOfRefItemList<ItemType::node>(); ++i_ref_node_list) { - const RefNodeList& ref_node_list = mesh.connectivity().refItemList<ItemType::node>(i_ref_node_list); - const RefId& ref = ref_node_list.refId(); - if (ref == sym_bc_descriptor.boundaryDescriptor()) { - SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = - new SymmetryBoundaryCondition<MeshType::Dimension>( - MeshFlatNodeBoundary<MeshType::Dimension>(mesh, ref_node_list)); - std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); - bc_list.push_back(BoundaryConditionHandler(bc)); - } + switch (p_mesh->dimension()) { + case 1: { + std::vector<std::string> sym_boundary_name_list = {"XMIN", "XMAX"}; + std::vector<std::shared_ptr<IBoundaryConditionDescriptor>> bc_descriptor_list; + for (const auto& sym_boundary_name : sym_boundary_name_list) { + std::shared_ptr<IBoundaryDescriptor> boudary_descriptor = + std::shared_ptr<IBoundaryDescriptor>(new NamedBoundaryDescriptor(sym_boundary_name)); + SymmetryBoundaryConditionDescriptor* sym_bc_descriptor = + new SymmetryBoundaryConditionDescriptor(boudary_descriptor); + + bc_descriptor_list.push_back(std::shared_ptr<IBoundaryConditionDescriptor>(sym_bc_descriptor)); + } + + using ConnectivityType = Connectivity1D; + using MeshType = Mesh<ConnectivityType>; + using MeshDataType = MeshData<1>; + using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; + + std::shared_ptr<const MeshType> mesh = std::dynamic_pointer_cast<const MeshType>(gmsh_reader.mesh()); + + Timer timer; + timer.reset(); + MeshDataType mesh_data(*mesh); + + std::vector<BoundaryConditionHandler> bc_list; + { + for (const auto& bc_descriptor : bc_descriptor_list) { + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = + dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); + for (size_t i_ref_node_list = 0; + i_ref_node_list < mesh->connectivity().numberOfRefItemList<ItemType::node>(); ++i_ref_node_list) { + const RefNodeList& ref_node_list = mesh->connectivity().refItemList<ItemType::node>(i_ref_node_list); + const RefId& ref = ref_node_list.refId(); + if (ref == sym_bc_descriptor.boundaryDescriptor()) { + SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = + new SymmetryBoundaryCondition<MeshType::Dimension>( + MeshFlatNodeBoundary<MeshType::Dimension>(mesh, ref_node_list)); + std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); + bc_list.push_back(BoundaryConditionHandler(bc)); } - break; - } - default: { - throw UnexpectedError("Unknown BCDescription\n"); - } } + break; + } + default: { + throw UnexpectedError("Unknown BCDescription\n"); + } } } + } - UnknownsType unknowns(mesh_data); - - unknowns.initializeSod(); - - AcousticSolver<MeshDataType> acoustic_solver(mesh_data, bc_list); + UnknownsType unknowns(mesh_data); - using Rd = TinyVector<MeshType::Dimension>; + unknowns.initializeSod(); - const CellValue<const double>& Vj = mesh_data.Vj(); + AcousticSolver acoustic_solver(mesh, bc_list); - const double tmax = 0.2; - double t = 0; + using Rd = TinyVector<MeshType::Dimension>; - int itermax = std::numeric_limits<int>::max(); - int iteration = 0; + const CellValue<const double>& Vj = mesh_data.Vj(); - CellValue<double>& rhoj = unknowns.rhoj(); - CellValue<double>& ej = unknowns.ej(); - CellValue<double>& pj = unknowns.pj(); - CellValue<double>& gammaj = unknowns.gammaj(); - CellValue<double>& cj = unknowns.cj(); + const double tmax = 0.2; + double t = 0; - BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); + int itermax = std::numeric_limits<int>::max(); + int iteration = 0; - VTKWriter vtk_writer("mesh", 0.01); + CellValue<double>& rhoj = unknowns.rhoj(); + CellValue<double>& ej = unknowns.ej(); + CellValue<double>& pj = unknowns.pj(); + CellValue<double>& gammaj = unknowns.gammaj(); + CellValue<double>& cj = unknowns.cj(); - while ((t < tmax) and (iteration < itermax)) { - vtk_writer.write(mesh, - {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", mesh.xr()}, - NamedItemValue{"cell_owner", mesh.connectivity().cellOwner()}, - NamedItemValue{"node_owner", mesh.connectivity().nodeOwner()}}, - t); - double dt = 0.4 * acoustic_solver.acoustic_dt(Vj, cj); - if (t + dt > tmax) { - dt = tmax - t; - } - acoustic_solver.computeNextStep(t, dt, unknowns); + BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); - block_eos.updatePandCFromRhoE(); + VTKWriter vtk_writer("mesh", 0.01); - t += dt; - ++iteration; - } + while ((t < tmax) and (iteration < itermax)) { vtk_writer.write(mesh, {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", mesh.xr()}, - NamedItemValue{"cell_owner", mesh.connectivity().cellOwner()}, - NamedItemValue{"node_owner", mesh.connectivity().nodeOwner()}}, - t, true); // forces last output - - std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset << ": " << rang::fgB::green - << t << rang::fg::reset << " (" << iteration << " iterations)\n"; - - method_cost_map["AcousticSolverWithMesh"] = timer.seconds(); - - { // gnuplot output for density - const CellValue<const Rd>& xj = mesh_data.xj(); - const CellValue<const double>& rhoj = unknowns.rhoj(); - std::ofstream fout("rho"); - for (CellId j = 0; j < mesh.numberOfCells(); ++j) { - fout << xj[j][0] << ' ' << rhoj[j] << '\n'; - } + NamedItemValue{"coords", mesh->xr()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t); + double dt = 0.4 * acoustic_solver.acoustic_dt(Vj, cj); + if (t + dt > tmax) { + dt = tmax - t; } + mesh = acoustic_solver.computeNextStep(dt, unknowns); + + block_eos.updatePandCFromRhoE(); - break; + t += dt; + ++iteration; } - case 2: { - // test case boundary condition description - std::vector<std::string> sym_boundary_name_list = {"XMIN", "XMAX", "YMIN", "YMAX"}; - std::vector<std::shared_ptr<BoundaryConditionDescriptor>> bc_descriptor_list; - for (const auto& sym_boundary_name : sym_boundary_name_list) { - std::shared_ptr<BoundaryDescriptor> boudary_descriptor = - std::shared_ptr<BoundaryDescriptor>(new NamedBoundaryDescriptor(sym_boundary_name)); - SymmetryBoundaryConditionDescriptor* sym_bc_descriptor = - new SymmetryBoundaryConditionDescriptor(boudary_descriptor); - - bc_descriptor_list.push_back(std::shared_ptr<BoundaryConditionDescriptor>(sym_bc_descriptor)); + vtk_writer.write(mesh, + {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, + NamedItemValue{"coords", mesh->xr()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t, true); // forces last output + + std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset << ": " << rang::fgB::green + << t << rang::fg::reset << " (" << iteration << " iterations)\n"; + + method_cost_map["AcousticSolverWithMesh"] = timer.seconds(); + + { // gnuplot output for density + const CellValue<const Rd>& xj = mesh_data.xj(); + const CellValue<const double>& rhoj = unknowns.rhoj(); + std::ofstream fout("rho"); + for (CellId j = 0; j < mesh->numberOfCells(); ++j) { + fout << xj[j][0] << ' ' << rhoj[j] << '\n'; } + } - using ConnectivityType = Connectivity2D; - using MeshType = Mesh<ConnectivityType>; - using MeshDataType = MeshData<MeshType>; - using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; - - const MeshType& mesh = dynamic_cast<const MeshType&>(*gmsh_reader.mesh()); - - Timer timer; - timer.reset(); - MeshDataType mesh_data(mesh); - - std::vector<BoundaryConditionHandler> bc_list; - { - for (const auto& bc_descriptor : bc_descriptor_list) { - switch (bc_descriptor->type()) { - case BoundaryConditionDescriptor::Type::symmetry: { - const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = - dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); - for (size_t i_ref_face_list = 0; - i_ref_face_list < mesh.connectivity().numberOfRefItemList<ItemType::face>(); ++i_ref_face_list) { - const RefFaceList& ref_face_list = mesh.connectivity().refItemList<ItemType::face>(i_ref_face_list); - const RefId& ref = ref_face_list.refId(); - if (ref == sym_bc_descriptor.boundaryDescriptor()) { - SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = - new SymmetryBoundaryCondition<MeshType::Dimension>( - MeshFlatNodeBoundary<MeshType::Dimension>(mesh, ref_face_list)); - std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); - bc_list.push_back(BoundaryConditionHandler(bc)); - } + break; + } + case 2: { + // test case boundary condition description + std::vector<std::string> sym_boundary_name_list = {"XMIN", "XMAX", "YMIN", "YMAX"}; + std::vector<std::shared_ptr<IBoundaryConditionDescriptor>> bc_descriptor_list; + for (const auto& sym_boundary_name : sym_boundary_name_list) { + std::shared_ptr<IBoundaryDescriptor> boudary_descriptor = + std::shared_ptr<IBoundaryDescriptor>(new NamedBoundaryDescriptor(sym_boundary_name)); + SymmetryBoundaryConditionDescriptor* sym_bc_descriptor = + new SymmetryBoundaryConditionDescriptor(boudary_descriptor); + + bc_descriptor_list.push_back(std::shared_ptr<IBoundaryConditionDescriptor>(sym_bc_descriptor)); + } + + using ConnectivityType = Connectivity2D; + using MeshType = Mesh<ConnectivityType>; + using MeshDataType = MeshData<2>; + using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; + + std::shared_ptr<const MeshType> mesh = std::dynamic_pointer_cast<const MeshType>(gmsh_reader.mesh()); + + Timer timer; + timer.reset(); + MeshDataType mesh_data(*mesh); + + std::vector<BoundaryConditionHandler> bc_list; + { + for (const auto& bc_descriptor : bc_descriptor_list) { + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = + dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); + for (size_t i_ref_face_list = 0; + i_ref_face_list < mesh->connectivity().numberOfRefItemList<ItemType::face>(); ++i_ref_face_list) { + const RefFaceList& ref_face_list = mesh->connectivity().refItemList<ItemType::face>(i_ref_face_list); + const RefId& ref = ref_face_list.refId(); + if (ref == sym_bc_descriptor.boundaryDescriptor()) { + SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = + new SymmetryBoundaryCondition<MeshType::Dimension>( + MeshFlatNodeBoundary<MeshType::Dimension>(mesh, ref_face_list)); + std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); + bc_list.push_back(BoundaryConditionHandler(bc)); } - break; - } - default: { - throw UnexpectedError("Unknown BCDescription\n"); - } } + break; + } + default: { + throw UnexpectedError("Unknown BCDescription\n"); + } } } + } - UnknownsType unknowns(mesh_data); - - unknowns.initializeSod(); - - AcousticSolver<MeshDataType> acoustic_solver(mesh_data, bc_list); + UnknownsType unknowns(mesh_data); - const CellValue<const double>& Vj = mesh_data.Vj(); + unknowns.initializeSod(); - const double tmax = 0.2; - double t = 0; + AcousticSolver acoustic_solver(mesh, bc_list); - int itermax = std::numeric_limits<int>::max(); - int iteration = 0; + const CellValue<const double>& Vj = mesh_data.Vj(); - CellValue<double>& rhoj = unknowns.rhoj(); - CellValue<double>& ej = unknowns.ej(); - CellValue<double>& pj = unknowns.pj(); - CellValue<double>& gammaj = unknowns.gammaj(); - CellValue<double>& cj = unknowns.cj(); + const double tmax = 0.2; + double t = 0; - BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); + int itermax = std::numeric_limits<int>::max(); + int iteration = 0; - VTKWriter vtk_writer("mesh", 0.01); + CellValue<double>& rhoj = unknowns.rhoj(); + CellValue<double>& ej = unknowns.ej(); + CellValue<double>& pj = unknowns.pj(); + CellValue<double>& gammaj = unknowns.gammaj(); + CellValue<double>& cj = unknowns.cj(); - while ((t < tmax) and (iteration < itermax)) { - vtk_writer.write(mesh, - {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", mesh.xr()}, - NamedItemValue{"cell_owner", mesh.connectivity().cellOwner()}, - NamedItemValue{"node_owner", mesh.connectivity().nodeOwner()}}, - t); - double dt = 0.4 * acoustic_solver.acoustic_dt(Vj, cj); - if (t + dt > tmax) { - dt = tmax - t; - } - acoustic_solver.computeNextStep(t, dt, unknowns); + BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); - block_eos.updatePandCFromRhoE(); + VTKWriter vtk_writer("mesh", 0.01); - t += dt; - ++iteration; - } + while ((t < tmax) and (iteration < itermax)) { vtk_writer.write(mesh, {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", mesh.xr()}, - NamedItemValue{"cell_owner", mesh.connectivity().cellOwner()}, - NamedItemValue{"node_owner", mesh.connectivity().nodeOwner()}}, - t, true); // forces last output + NamedItemValue{"coords", mesh->xr()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t); + double dt = 0.4 * acoustic_solver.acoustic_dt(Vj, cj); + if (t + dt > tmax) { + dt = tmax - t; + } + mesh = acoustic_solver.computeNextStep(dt, unknowns); - std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset << ": " << rang::fgB::green - << t << rang::fg::reset << " (" << iteration << " iterations)\n"; + block_eos.updatePandCFromRhoE(); - method_cost_map["AcousticSolverWithMesh"] = timer.seconds(); - break; + t += dt; + ++iteration; + } + vtk_writer.write(mesh, + {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, + NamedItemValue{"coords", mesh->xr()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t, true); // forces last output + + std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset << ": " << rang::fgB::green + << t << rang::fg::reset << " (" << iteration << " iterations)\n"; + + method_cost_map["AcousticSolverWithMesh"] = timer.seconds(); + break; + } + case 3: { + std::vector<std::string> sym_boundary_name_list = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; + std::vector<std::shared_ptr<IBoundaryConditionDescriptor>> bc_descriptor_list; + for (const auto& sym_boundary_name : sym_boundary_name_list) { + std::shared_ptr<IBoundaryDescriptor> boudary_descriptor = + std::shared_ptr<IBoundaryDescriptor>(new NamedBoundaryDescriptor(sym_boundary_name)); + SymmetryBoundaryConditionDescriptor* sym_bc_descriptor = + new SymmetryBoundaryConditionDescriptor(boudary_descriptor); + + bc_descriptor_list.push_back(std::shared_ptr<IBoundaryConditionDescriptor>(sym_bc_descriptor)); } - case 3: { - std::vector<std::string> sym_boundary_name_list = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - std::vector<std::shared_ptr<BoundaryConditionDescriptor>> bc_descriptor_list; - for (const auto& sym_boundary_name : sym_boundary_name_list) { - std::shared_ptr<BoundaryDescriptor> boudary_descriptor = - std::shared_ptr<BoundaryDescriptor>(new NamedBoundaryDescriptor(sym_boundary_name)); - SymmetryBoundaryConditionDescriptor* sym_bc_descriptor = - new SymmetryBoundaryConditionDescriptor(boudary_descriptor); - - bc_descriptor_list.push_back(std::shared_ptr<BoundaryConditionDescriptor>(sym_bc_descriptor)); - } - using ConnectivityType = Connectivity3D; - using MeshType = Mesh<ConnectivityType>; - using MeshDataType = MeshData<MeshType>; - using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; - - const MeshType& mesh = dynamic_cast<const MeshType&>(*gmsh_reader.mesh()); - - Timer timer; - timer.reset(); - MeshDataType mesh_data(mesh); - - std::vector<BoundaryConditionHandler> bc_list; - { - for (const auto& bc_descriptor : bc_descriptor_list) { - switch (bc_descriptor->type()) { - case BoundaryConditionDescriptor::Type::symmetry: { - const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = - dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); - for (size_t i_ref_face_list = 0; - i_ref_face_list < mesh.connectivity().numberOfRefItemList<ItemType::face>(); ++i_ref_face_list) { - const RefFaceList& ref_face_list = mesh.connectivity().refItemList<ItemType::face>(i_ref_face_list); - const RefId& ref = ref_face_list.refId(); - if (ref == sym_bc_descriptor.boundaryDescriptor()) { - SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = - new SymmetryBoundaryCondition<MeshType::Dimension>( - MeshFlatNodeBoundary<MeshType::Dimension>(mesh, ref_face_list)); - std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); - bc_list.push_back(BoundaryConditionHandler(bc)); - } + using ConnectivityType = Connectivity3D; + using MeshType = Mesh<ConnectivityType>; + using MeshDataType = MeshData<3>; + using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; + + std::shared_ptr<const MeshType> mesh = std::dynamic_pointer_cast<const MeshType>(gmsh_reader.mesh()); + + Timer timer; + timer.reset(); + MeshDataType mesh_data(*mesh); + + std::vector<BoundaryConditionHandler> bc_list; + { + for (const auto& bc_descriptor : bc_descriptor_list) { + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = + dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); + for (size_t i_ref_face_list = 0; + i_ref_face_list < mesh->connectivity().numberOfRefItemList<ItemType::face>(); ++i_ref_face_list) { + const RefFaceList& ref_face_list = mesh->connectivity().refItemList<ItemType::face>(i_ref_face_list); + const RefId& ref = ref_face_list.refId(); + if (ref == sym_bc_descriptor.boundaryDescriptor()) { + SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = + new SymmetryBoundaryCondition<MeshType::Dimension>( + MeshFlatNodeBoundary<MeshType::Dimension>(mesh, ref_face_list)); + std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); + bc_list.push_back(BoundaryConditionHandler(bc)); } - break; - } - default: { - throw UnexpectedError("Unknown BCDescription\n"); - } } + break; + } + default: { + throw UnexpectedError("Unknown BCDescription\n"); + } } } + } - UnknownsType unknowns(mesh_data); - - unknowns.initializeSod(); + UnknownsType unknowns(mesh_data); - AcousticSolver<MeshDataType> acoustic_solver(mesh_data, bc_list); + unknowns.initializeSod(); - const CellValue<const double>& Vj = mesh_data.Vj(); + AcousticSolver acoustic_solver(mesh, bc_list); - const double tmax = 0.2; - double t = 0; + const CellValue<const double>& Vj = mesh_data.Vj(); - int itermax = std::numeric_limits<int>::max(); - int iteration = 0; + const double tmax = 0.2; + double t = 0; - CellValue<double>& rhoj = unknowns.rhoj(); - CellValue<double>& ej = unknowns.ej(); - CellValue<double>& pj = unknowns.pj(); - CellValue<double>& gammaj = unknowns.gammaj(); - CellValue<double>& cj = unknowns.cj(); + int itermax = std::numeric_limits<int>::max(); + int iteration = 0; - BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); + CellValue<double>& rhoj = unknowns.rhoj(); + CellValue<double>& ej = unknowns.ej(); + CellValue<double>& pj = unknowns.pj(); + CellValue<double>& gammaj = unknowns.gammaj(); + CellValue<double>& cj = unknowns.cj(); - VTKWriter vtk_writer("mesh", 0.01); + BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); - while ((t < tmax) and (iteration < itermax)) { - vtk_writer.write(mesh, - {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", mesh.xr()}, - NamedItemValue{"cell_owner", mesh.connectivity().cellOwner()}, - NamedItemValue{"node_owner", mesh.connectivity().nodeOwner()}}, - t); - double dt = 0.4 * acoustic_solver.acoustic_dt(Vj, cj); - if (t + dt > tmax) { - dt = tmax - t; - } - acoustic_solver.computeNextStep(t, dt, unknowns); - block_eos.updatePandCFromRhoE(); + VTKWriter vtk_writer("mesh", 0.01); - t += dt; - ++iteration; - } + while ((t < tmax) and (iteration < itermax)) { vtk_writer.write(mesh, {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", mesh.xr()}, - NamedItemValue{"cell_owner", mesh.connectivity().cellOwner()}, - NamedItemValue{"node_owner", mesh.connectivity().nodeOwner()}}, - t, true); // forces last output - - std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset << ": " << rang::fgB::green - << t << rang::fg::reset << " (" << iteration << " iterations)\n"; + NamedItemValue{"coords", mesh->xr()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t); + double dt = 0.4 * acoustic_solver.acoustic_dt(Vj, cj); + if (t + dt > tmax) { + dt = tmax - t; + } + mesh = acoustic_solver.computeNextStep(dt, unknowns); + block_eos.updatePandCFromRhoE(); - method_cost_map["AcousticSolverWithMesh"] = timer.seconds(); - break; - } + t += dt; + ++iteration; } - - std::cout << "* " << rang::fgB::red << "Could not be uglier!" << rang::fg::reset << " (" << __FILE__ << ':' - << __LINE__ << ")\n"; - - } else { - throw NormalError("Connectivity1D defined by number of nodes no more implemented\n"); + vtk_writer.write(mesh, + {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, + NamedItemValue{"coords", mesh->xr()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t, true); // forces last output + + std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset << ": " << rang::fgB::green + << t << rang::fg::reset << " (" << iteration << " iterations)\n"; + + method_cost_map["AcousticSolverWithMesh"] = timer.seconds(); + break; + } } - SynchronizerManager::destroy(); + std::cout << "* " << rang::fgB::red << "Could not be uglier!" << rang::fg::reset << " (" << __FILE__ << ':' + << __LINE__ << ")\n"; - finalize(); + } else { + throw NormalError("Connectivity1D defined by number of nodes no more implemented\n"); + } - std::string::size_type size = 0; - for (const auto& method_cost : method_cost_map) { - size = std::max(size, method_cost.first.size()); - } + MeshDataManager::destroy(); + SynchronizerManager::destroy(); - for (const auto& method_cost : method_cost_map) { - std::cout << "* [" << rang::fgB::cyan << std::setw(size) << std::left << method_cost.first << rang::fg::reset - << "] Execution time: " << rang::style::bold << method_cost.second << rang::style::reset << '\n'; - } + finalize(); + + std::string::size_type size = 0; + for (const auto& method_cost : method_cost_map) { + size = std::max(size, method_cost.first.size()); } - catch (const IExitError& e) { - if (SignalManager::pauseOnError()) { - std::rethrow_exception(std::current_exception()); - } else { - // Each failing process must write - std::cerr.setstate(std::ios::goodbit); - std::cerr << e.what() << '\n'; - - return 1; - } + + for (const auto& method_cost : method_cost_map) { + std::cout << "* [" << rang::fgB::cyan << std::setw(size) << std::left << method_cost.first << rang::fg::reset + << "] Execution time: " << rang::style::bold << method_cost.second << rang::style::reset << '\n'; } return 0; diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt index 73d686fb20c158ad2693daa28124081902310f61..92c865c599767db0d5e5fed84e7d16d0cbec8579 100644 --- a/src/mesh/CMakeLists.txt +++ b/src/mesh/CMakeLists.txt @@ -2,10 +2,18 @@ add_library( PugsMesh + CartesianMeshBuilder.cpp Connectivity.cpp + ConnectivityBuilderBase.cpp ConnectivityComputer.cpp - GmshReader.cpp ConnectivityDispatcher.cpp + DiamondDualConnectivityBuilder.cpp + DiamondDualMeshBuilder.cpp + GmshReader.cpp + IMesh.cpp + LogicalConnectivityBuilder.cpp + MeshBuilderBase.cpp + MeshDataManager.cpp SynchronizerManager.cpp) # Additional dependencies diff --git a/src/mesh/CartesianMeshBuilder.cpp b/src/mesh/CartesianMeshBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6a4589cced3958ca7401a5a80d881d23fe87749 --- /dev/null +++ b/src/mesh/CartesianMeshBuilder.cpp @@ -0,0 +1,160 @@ +#include <mesh/CartesianMeshBuilder.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/LogicalConnectivityBuilder.hpp> +#include <mesh/RefId.hpp> +#include <utils/Array.hpp> +#include <utils/Messenger.hpp> + +template <size_t Dimension> +NodeValue<TinyVector<Dimension>> +CartesianMeshBuilder::_getNodeCoordinates(const TinyVector<Dimension>&, + const TinyVector<Dimension>&, + const TinyVector<Dimension, uint64_t>&, + const IConnectivity&) const +{ + static_assert(Dimension <= 3, "invalid dimension"); +} + +template <> +NodeValue<TinyVector<1>> +CartesianMeshBuilder::_getNodeCoordinates(const TinyVector<1>& a, + const TinyVector<1>& b, + const TinyVector<1, uint64_t>& cell_size, + const IConnectivity& connectivity) const +{ + const double h = (b[0] - a[0]) / cell_size[0]; + NodeValue<TinyVector<1>> xr(connectivity); + parallel_for( + connectivity.numberOfNodes(), PUGS_LAMBDA(NodeId r) { xr[r] = a + r * h; }); + + return xr; +} + +template <> +NodeValue<TinyVector<2>> +CartesianMeshBuilder::_getNodeCoordinates(const TinyVector<2>& a, + const TinyVector<2>& b, + const TinyVector<2, uint64_t>& cell_size, + const IConnectivity& connectivity) const +{ + const TinyVector<2> h{(b[0] - a[0]) / cell_size[0], (b[1] - a[1]) / cell_size[1]}; + + const TinyVector<2, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1}; + + const auto node_logic_id = [&](size_t r) { + const uint64_t r0 = r / node_size[1]; + const uint64_t r1 = r % node_size[1]; + return TinyVector<2, uint64_t>{r0, r1}; + }; + + NodeValue<TinyVector<2>> xr(connectivity); + + parallel_for( + connectivity.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + const TinyVector<2, uint64_t> node_index = node_logic_id(r); + for (size_t i = 0; i < 2; ++i) { + xr[r][i] = a[i] + node_index[i] * h[i]; + } + }); + + return xr; +} + +template <> +NodeValue<TinyVector<3>> +CartesianMeshBuilder::_getNodeCoordinates(const TinyVector<3>& a, + const TinyVector<3>& b, + const TinyVector<3, uint64_t>& cell_size, + const IConnectivity& connectivity) const +{ + const TinyVector<3, uint64_t> node_size = [&] { + TinyVector node_size{cell_size}; + for (size_t i = 0; i < 3; ++i) { + node_size[i] += 1; + } + return node_size; + }(); + + const auto node_logic_id = [&](size_t r) { + const size_t slice1 = node_size[1] * node_size[2]; + const size_t& slice2 = node_size[2]; + const uint64_t r0 = r / slice1; + const uint64_t r1 = (r - r0 * slice1) / slice2; + const uint64_t r2 = r - (r0 * slice1 + r1 * slice2); + return TinyVector<3, uint64_t>{r0, r1, r2}; + }; + + const TinyVector<3> h{(b[0] - a[0]) / cell_size[0], (b[1] - a[1]) / cell_size[1], (b[2] - a[2]) / cell_size[2]}; + + NodeValue<TinyVector<3>> xr(connectivity); + parallel_for( + connectivity.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + const TinyVector<3, uint64_t> node_index = node_logic_id(r); + for (size_t i = 0; i < 3; ++i) { + xr[r][i] = a[i] + node_index[i] * h[i]; + } + }); + + return xr; +} + +template <size_t Dimension> +void +CartesianMeshBuilder::_buildCartesianMesh(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension, uint64_t>& cell_size) +{ + static_assert(Dimension <= 3, "unexpected dimension"); + + LogicalConnectivityBuilder logical_connectivity_builder{cell_size}; + + using ConnectivityType = Connectivity<Dimension>; + + std::shared_ptr<const ConnectivityType> p_connectivity = + std::dynamic_pointer_cast<const ConnectivityType>(logical_connectivity_builder.connectivity()); + const ConnectivityType& connectivity = *p_connectivity; + + NodeValue<TinyVector<Dimension>> xr = _getNodeCoordinates(a, b, cell_size, connectivity); + + m_mesh = std::make_shared<Mesh<ConnectivityType>>(p_connectivity, xr); +} + +template <size_t Dimension> +CartesianMeshBuilder::CartesianMeshBuilder(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension, uint64_t>& size) +{ + if (parallel::rank() == 0) { + TinyVector lenght = b - a; + for (size_t i = 0; i < Dimension; ++i) { + if (lenght[i] == 0) { + throw NormalError("invalid box definition corners share a component"); + } + } + + TinyVector<Dimension> corner0 = a; + TinyVector<Dimension> corner1 = b; + + for (size_t i = 0; i < Dimension; ++i) { + if (corner0[i] > corner1[i]) { + std::swap(corner0[i], corner1[i]); + } + } + + this->_buildCartesianMesh(corner0, corner1, size); + } + this->_dispatch<Dimension>(); +} + +template CartesianMeshBuilder::CartesianMeshBuilder(const TinyVector<1>&, + const TinyVector<1>&, + const TinyVector<1, uint64_t>&); + +template CartesianMeshBuilder::CartesianMeshBuilder(const TinyVector<2>&, + const TinyVector<2>&, + const TinyVector<2, uint64_t>&); + +template CartesianMeshBuilder::CartesianMeshBuilder(const TinyVector<3>&, + const TinyVector<3>&, + const TinyVector<3, uint64_t>&); diff --git a/src/mesh/CartesianMeshBuilder.hpp b/src/mesh/CartesianMeshBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7b32b55b64d021c655ff9c35245ece4b31b2ed76 --- /dev/null +++ b/src/mesh/CartesianMeshBuilder.hpp @@ -0,0 +1,32 @@ +#ifndef CARTESIAN_MESH_BUILDER_HPP +#define CARTESIAN_MESH_BUILDER_HPP + +#include <algebra/TinyVector.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshBuilderBase.hpp> + +#include <memory> + +class CartesianMeshBuilder : public MeshBuilderBase +{ + private: + template <size_t Dimension> + void _buildCartesianMesh(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension, uint64_t>& size); + + template <size_t Dimension> + NodeValue<TinyVector<Dimension>> _getNodeCoordinates(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension, uint64_t>& size, + const IConnectivity& connectivity) const; + + public: + template <size_t Dimension> + CartesianMeshBuilder(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension, uint64_t>& size); + ~CartesianMeshBuilder() = default; +}; + +#endif // CARTESIAN_MESH_BUILDER_HPP diff --git a/src/mesh/CellType.hpp b/src/mesh/CellType.hpp index f0f214a60d9e9fb214e221b7dac1516b9c69b778..3a0f01520bba191ff4535dfb407ddda55edab3c9 100644 --- a/src/mesh/CellType.hpp +++ b/src/mesh/CellType.hpp @@ -12,10 +12,11 @@ enum class CellType : unsigned short Triangle, Quadrangle, - Tetrahedron, - Pyramid, + Diamond, + Hexahedron, Prism, - Hexahedron + Pyramid, + Tetrahedron }; PUGS_INLINE @@ -29,14 +30,16 @@ name(CellType cell_type) return "triangle"; case CellType::Quadrangle: return "quadrangle"; - case CellType::Tetrahedron: - return "tetrahedron"; - case CellType::Pyramid: - return "pyramid"; - case CellType::Prism: - return "prism"; + case CellType::Diamond: + return "diamond"; case CellType::Hexahedron: return "hexahedron"; + case CellType::Prism: + return "prism"; + case CellType::Pyramid: + return "pyramid"; + case CellType::Tetrahedron: + return "tetrahedron"; default: return "unknown cell type"; } diff --git a/src/mesh/Connectivity.cpp b/src/mesh/Connectivity.cpp index a011948482bc8a9b1b562da6625a11a77e6a5b9b..de8be58168d312e083516e2824e5eec45a484e3c 100644 --- a/src/mesh/Connectivity.cpp +++ b/src/mesh/Connectivity.cpp @@ -163,10 +163,10 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) } } -template Connectivity1D::Connectivity(); -template Connectivity2D::Connectivity(); -template Connectivity3D::Connectivity(); +template Connectivity<1>::Connectivity(); +template Connectivity<2>::Connectivity(); +template Connectivity<3>::Connectivity(); -template void Connectivity1D::_buildFrom(const ConnectivityDescriptor&); -template void Connectivity2D::_buildFrom(const ConnectivityDescriptor&); -template void Connectivity3D::_buildFrom(const ConnectivityDescriptor&); +template void Connectivity<1>::_buildFrom(const ConnectivityDescriptor&); +template void Connectivity<2>::_buildFrom(const ConnectivityDescriptor&); +template void Connectivity<3>::_buildFrom(const ConnectivityDescriptor&); diff --git a/src/mesh/ConnectivityBuilderBase.cpp b/src/mesh/ConnectivityBuilderBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5d47e25003a710e1e2c18ba6b772ffd04bb532f --- /dev/null +++ b/src/mesh/ConnectivityBuilderBase.cpp @@ -0,0 +1,416 @@ +#include <mesh/ConnectivityBuilderBase.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityDescriptor.hpp> +#include <mesh/ConnectivityDispatcher.hpp> +#include <mesh/ItemId.hpp> +#include <mesh/Mesh.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +#include <vector> + +template <size_t Dimension> +void +ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& descriptor) +{ + static_assert((Dimension == 2) or (Dimension == 3), "Invalid dimension to compute cell-face connectivities"); + using CellFaceInfo = std::tuple<CellId, unsigned short, bool>; + using Face = ConnectivityFace<Dimension>; + + const auto& node_number_vector = descriptor.node_number_vector; + Array<unsigned short> cell_nb_faces(descriptor.cell_to_node_vector.size()); + std::map<Face, std::vector<CellFaceInfo>> face_cells_map; + for (CellId j = 0; j < descriptor.cell_to_node_vector.size(); ++j) { + const auto& cell_nodes = descriptor.cell_to_node_vector[j]; + + if constexpr (Dimension == 2) { + switch (descriptor.cell_type_vector[j]) { + case CellType::Triangle: { + cell_nb_faces[j] = 3; + // face 0 + Face f0({cell_nodes[1], cell_nodes[2]}, node_number_vector); + face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); + + // face 1 + Face f1({cell_nodes[2], cell_nodes[0]}, node_number_vector); + face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); + + // face 2 + Face f2({cell_nodes[0], cell_nodes[1]}, node_number_vector); + face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + break; + } + case CellType::Quadrangle: { + cell_nb_faces[j] = 4; + // face 0 + Face f0({cell_nodes[0], cell_nodes[1]}, node_number_vector); + face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); + + // face 1 + Face f1({cell_nodes[1], cell_nodes[2]}, node_number_vector); + face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); + + // face 2 + Face f2({cell_nodes[2], cell_nodes[3]}, node_number_vector); + face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + + // face 3 + Face f3({cell_nodes[3], cell_nodes[0]}, node_number_vector); + face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); + break; + } + default: { + std::ostringstream error_msg; + error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 2"; + throw UnexpectedError(error_msg.str()); + } + } + } else if constexpr (Dimension == 3) { + switch (descriptor.cell_type_vector[j]) { + case CellType::Hexahedron: { + // face 0 + Face f0({cell_nodes[3], cell_nodes[2], cell_nodes[1], cell_nodes[0]}, node_number_vector); + face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); + + // face 1 + Face f1({cell_nodes[4], cell_nodes[5], cell_nodes[6], cell_nodes[7]}, node_number_vector); + face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); + + // face 2 + Face f2({cell_nodes[0], cell_nodes[4], cell_nodes[7], cell_nodes[3]}, node_number_vector); + face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + + // face 3 + Face f3({cell_nodes[1], cell_nodes[2], cell_nodes[6], cell_nodes[5]}, node_number_vector); + face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); + + // face 4 + Face f4({cell_nodes[0], cell_nodes[1], cell_nodes[5], cell_nodes[4]}, node_number_vector); + face_cells_map[f4].emplace_back(std::make_tuple(j, 4, f4.reversed())); + + // face 5 + Face f5({cell_nodes[3], cell_nodes[7], cell_nodes[6], cell_nodes[2]}, node_number_vector); + face_cells_map[f5].emplace_back(std::make_tuple(j, 5, f5.reversed())); + + cell_nb_faces[j] = 6; + break; + } + case CellType::Tetrahedron: { + cell_nb_faces[j] = 4; + // face 0 + Face f0({cell_nodes[1], cell_nodes[2], cell_nodes[3]}, node_number_vector); + face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); + + // face 1 + Face f1({cell_nodes[0], cell_nodes[3], cell_nodes[2]}, node_number_vector); + face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); + + // face 2 + Face f2({cell_nodes[0], cell_nodes[1], cell_nodes[3]}, node_number_vector); + face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + + // face 3 + Face f3({cell_nodes[0], cell_nodes[2], cell_nodes[1]}, node_number_vector); + face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); + break; + } + case CellType::Pyramid: { + cell_nb_faces[j] = cell_nodes.size(); + std::vector<unsigned int> base_nodes; + std::copy_n(cell_nodes.begin(), cell_nodes.size() - 1, std::back_inserter(base_nodes)); + + // base face + { + Face base_face(base_nodes, node_number_vector); + face_cells_map[base_face].emplace_back(std::make_tuple(j, 0, base_face.reversed())); + } + // side faces + const auto pyramid_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i_node = 0; i_node < base_nodes.size(); ++i_node) { + Face side_face({base_nodes[(i_node + 1) % base_nodes.size()], base_nodes[i_node], pyramid_vertex}, + node_number_vector); + face_cells_map[side_face].emplace_back(std::make_tuple(j, i_node + 1, side_face.reversed())); + } + break; + } + case CellType::Diamond: { + cell_nb_faces[j] = 2 * (cell_nodes.size() - 2); + std::vector<unsigned int> base_nodes; + std::copy_n(cell_nodes.begin() + 1, cell_nodes.size() - 2, std::back_inserter(base_nodes)); + + { // top faces + const auto top_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i_node = 0; i_node < base_nodes.size(); ++i_node) { + Face top_face({base_nodes[i_node], base_nodes[(i_node + 1) % base_nodes.size()], top_vertex}, + node_number_vector); + face_cells_map[top_face].emplace_back(std::make_tuple(j, i_node, top_face.reversed())); + } + } + + { // bottom faces + const auto bottom_vertex = cell_nodes[0]; + for (size_t i_node = 0; i_node < base_nodes.size(); ++i_node) { + Face bottom_face({base_nodes[(i_node + 1) % base_nodes.size()], base_nodes[i_node], bottom_vertex}, + node_number_vector); + face_cells_map[bottom_face].emplace_back( + std::make_tuple(j, i_node + base_nodes.size(), bottom_face.reversed())); + } + } + break; + } + default: { + std::ostringstream error_msg; + error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 3"; + throw UnexpectedError(error_msg.str()); + } + } + } + } + + { + descriptor.cell_to_face_vector.resize(descriptor.cell_to_node_vector.size()); + for (CellId j = 0; j < descriptor.cell_to_face_vector.size(); ++j) { + descriptor.cell_to_face_vector[j].resize(cell_nb_faces[j]); + } + FaceId l = 0; + for (const auto& face_cells_vector : face_cells_map) { + const auto& cells_vector = face_cells_vector.second; + for (unsigned short lj = 0; lj < cells_vector.size(); ++lj) { + const auto& [cell_number, cell_local_face, reversed] = cells_vector[lj]; + descriptor.cell_to_face_vector[cell_number][cell_local_face] = l; + } + ++l; + } + } + + { + descriptor.cell_face_is_reversed_vector.resize(descriptor.cell_to_node_vector.size()); + for (CellId j = 0; j < descriptor.cell_face_is_reversed_vector.size(); ++j) { + descriptor.cell_face_is_reversed_vector[j] = Array<bool>(cell_nb_faces[j]); + } + for (const auto& face_cells_vector : face_cells_map) { + const auto& cells_vector = face_cells_vector.second; + for (unsigned short lj = 0; lj < cells_vector.size(); ++lj) { + const auto& [cell_number, cell_local_face, reversed] = cells_vector[lj]; + descriptor.cell_face_is_reversed_vector[cell_number][cell_local_face] = reversed; + } + } + } + + { + descriptor.face_to_node_vector.resize(face_cells_map.size()); + int l = 0; + for (const auto& face_info : face_cells_map) { + const Face& face = face_info.first; + descriptor.face_to_node_vector[l] = face.nodeIdList(); + ++l; + } + } + + { + // Face numbers may change if numbers are provided in the file + descriptor.face_number_vector.resize(face_cells_map.size()); + for (size_t l = 0; l < face_cells_map.size(); ++l) { + descriptor.face_number_vector[l] = l; + } + } +} + +template <size_t Dimension> +void +ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(ConnectivityDescriptor& descriptor) +{ + static_assert(Dimension == 3, "Invalid dimension to compute face-edge connectivities"); + using FaceEdgeInfo = std::tuple<FaceId, unsigned short, bool>; + using Edge = ConnectivityFace<2>; + + const auto& node_number_vector = descriptor.node_number_vector; + Array<unsigned short> face_nb_edges(descriptor.face_to_node_vector.size()); + std::map<Edge, std::vector<FaceEdgeInfo>> edge_faces_map; + for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { + const auto& face_nodes = descriptor.face_to_node_vector[l]; + + face_nb_edges[l] = face_nodes.size(); + for (size_t r = 0; r < face_nodes.size() - 1; ++r) { + Edge e({face_nodes[r], face_nodes[r + 1]}, node_number_vector); + edge_faces_map[e].emplace_back(std::make_tuple(l, r, e.reversed())); + } + { + Edge e({face_nodes[face_nodes.size() - 1], face_nodes[0]}, node_number_vector); + edge_faces_map[e].emplace_back(std::make_tuple(l, face_nodes.size() - 1, e.reversed())); + } + } + + std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_id_map; + { + descriptor.face_to_edge_vector.resize(descriptor.face_to_node_vector.size()); + for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { + descriptor.face_to_edge_vector[l].resize(face_nb_edges[l]); + } + EdgeId e = 0; + for (const auto& edge_faces_vector : edge_faces_map) { + const auto& faces_vector = edge_faces_vector.second; + for (unsigned short l = 0; l < faces_vector.size(); ++l) { + const auto& [face_number, face_local_edge, reversed] = faces_vector[l]; + descriptor.face_to_edge_vector[face_number][face_local_edge] = e; + } + edge_id_map[edge_faces_vector.first] = e; + ++e; + } + } + + { + descriptor.face_edge_is_reversed_vector.resize(descriptor.face_to_node_vector.size()); + for (FaceId j = 0; j < descriptor.face_edge_is_reversed_vector.size(); ++j) { + descriptor.face_edge_is_reversed_vector[j] = Array<bool>(face_nb_edges[j]); + } + for (const auto& edge_faces_vector : edge_faces_map) { + const auto& faces_vector = edge_faces_vector.second; + for (unsigned short lj = 0; lj < faces_vector.size(); ++lj) { + const auto& [face_number, face_local_edge, reversed] = faces_vector[lj]; + descriptor.face_edge_is_reversed_vector[face_number][face_local_edge] = reversed; + } + } + } + + { + descriptor.edge_to_node_vector.resize(edge_faces_map.size()); + int e = 0; + for (const auto& edge_info : edge_faces_map) { + const Edge& edge = edge_info.first; + descriptor.edge_to_node_vector[e] = edge.nodeIdList(); + ++e; + } + } + + { + // Edge numbers may change if numbers are provided in the file + descriptor.edge_number_vector.resize(edge_faces_map.size()); + for (size_t e = 0; e < edge_faces_map.size(); ++e) { + descriptor.edge_number_vector[e] = e; + } + } + + { + descriptor.cell_to_edge_vector.reserve(descriptor.cell_to_node_vector.size()); + for (CellId j = 0; j < descriptor.cell_to_node_vector.size(); ++j) { + const auto& cell_nodes = descriptor.cell_to_node_vector[j]; + + switch (descriptor.cell_type_vector[j]) { + case CellType::Tetrahedron: { + constexpr int local_edge[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {2, 3}, {3, 1}}; + std::vector<unsigned int> cell_edge_vector; + cell_edge_vector.reserve(6); + for (int i_edge = 0; i_edge < 6; ++i_edge) { + const auto e = local_edge[i_edge]; + Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); + break; + } + case CellType::Hexahedron: { + constexpr int local_edge[12][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, + {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; + std::vector<unsigned int> cell_edge_vector; + cell_edge_vector.reserve(12); + for (int i_edge = 0; i_edge < 12; ++i_edge) { + const auto e = local_edge[i_edge]; + Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); + break; + } + case CellType::Pyramid: { + const size_t number_of_edges = 2 * cell_nodes.size(); + std::vector<unsigned int> base_nodes; + std::copy_n(cell_nodes.begin(), cell_nodes.size() - 1, std::back_inserter(base_nodes)); + + std::vector<unsigned int> cell_edge_vector; + cell_edge_vector.reserve(number_of_edges); + for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { + Edge edge{{base_nodes[i_edge], base_nodes[(i_edge + 1) % base_nodes.size()]}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + + const unsigned int top_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { + Edge edge{{base_nodes[i_edge], top_vertex}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); + break; + } + case CellType::Diamond: { + const size_t number_of_edges = 3 * cell_nodes.size(); + std::vector<unsigned int> base_nodes; + std::copy_n(cell_nodes.begin() + 1, cell_nodes.size() - 2, std::back_inserter(base_nodes)); + + std::vector<unsigned int> cell_edge_vector; + cell_edge_vector.reserve(number_of_edges); + for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { + Edge edge{{base_nodes[i_edge], base_nodes[(i_edge + 1) % base_nodes.size()]}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + + const unsigned int top_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { + Edge edge{{base_nodes[i_edge], top_vertex}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + + const unsigned int bottom_vertex = cell_nodes[0]; + for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { + Edge edge{{base_nodes[i_edge], bottom_vertex}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + + descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); + + break; + } + default: { + std::stringstream error_msg; + error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 3"; + throw NotImplementedError(error_msg.str()); + } + } + } + } +} + +template void ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<2>(ConnectivityDescriptor& descriptor); +template void ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<3>(ConnectivityDescriptor& descriptor); + +template void ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<3>( + ConnectivityDescriptor& descriptor); diff --git a/src/mesh/ConnectivityBuilderBase.hpp b/src/mesh/ConnectivityBuilderBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9b0d28a7a9389093348648573c85875f1e4a7de --- /dev/null +++ b/src/mesh/ConnectivityBuilderBase.hpp @@ -0,0 +1,226 @@ +#ifndef CONNECTIVITY_BUILDER_BASE_HPP +#define CONNECTIVITY_BUILDER_BASE_HPP + +#include <mesh/IConnectivity.hpp> + +#include <mesh/ItemId.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +#include <memory> +#include <vector> + +class ConnectivityDescriptor; + +class ConnectivityBuilderBase +{ + protected: + template <size_t Dimension> + class ConnectivityFace; + + std::shared_ptr<const IConnectivity> m_connectivity; + + template <size_t Dimension> + static void _computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& descriptor); + + template <size_t Dimension> + static void _computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(ConnectivityDescriptor& descriptor); + + public: + std::shared_ptr<const IConnectivity> + connectivity() const + { + return m_connectivity; + } + + ConnectivityBuilderBase() = default; + ~ConnectivityBuilderBase() = default; +}; + +template <> +class ConnectivityBuilderBase::ConnectivityFace<2> +{ + public: + friend struct Hash; + + struct Hash + { + size_t + operator()(const ConnectivityFace& f) const + { + size_t hash = 0; + hash ^= std::hash<unsigned int>()(f.m_node0_id); + hash ^= std::hash<unsigned int>()(f.m_node1_id) >> 1; + return hash; + } + }; + + private: + const std::vector<int>& m_node_number_vector; + + unsigned int m_node0_id; + unsigned int m_node1_id; + + bool m_reversed; + + public: + std::vector<unsigned int> + nodeIdList() const + { + return {m_node0_id, m_node1_id}; + } + + bool + reversed() const + { + return m_reversed; + } + + PUGS_INLINE + bool + operator==(const ConnectivityFace& f) const + { + return ((m_node0_id == f.m_node0_id) and (m_node1_id == f.m_node1_id)); + } + + PUGS_INLINE + bool + operator<(const ConnectivityFace& f) const + { + return ((m_node_number_vector[m_node0_id] < m_node_number_vector[f.m_node0_id]) or + ((m_node_number_vector[m_node0_id] == m_node_number_vector[f.m_node0_id]) and + (m_node_number_vector[m_node1_id] < m_node_number_vector[f.m_node1_id]))); + } + + PUGS_INLINE + ConnectivityFace(const std::vector<unsigned int>& node_id_list, const std::vector<int>& node_number_vector) + : m_node_number_vector(node_number_vector) + { + Assert(node_id_list.size() == 2); + + if (m_node_number_vector[node_id_list[0]] < m_node_number_vector[node_id_list[1]]) { + m_node0_id = node_id_list[0]; + m_node1_id = node_id_list[1]; + m_reversed = false; + } else { + m_node0_id = node_id_list[1]; + m_node1_id = node_id_list[0]; + m_reversed = true; + } + } + + PUGS_INLINE + ConnectivityFace(const ConnectivityFace&) = default; + + PUGS_INLINE + ~ConnectivityFace() = default; +}; + +template <> +class ConnectivityBuilderBase::ConnectivityFace<3> +{ + public: + friend struct Hash; + + struct Hash + { + size_t + operator()(const ConnectivityFace& f) const + { + size_t hash = 0; + for (size_t i = 0; i < f.m_node_id_list.size(); ++i) { + hash ^= std::hash<unsigned int>()(f.m_node_id_list[i]) >> i; + } + return hash; + } + }; + + private: + bool m_reversed; + std::vector<NodeId::base_type> m_node_id_list; + const std::vector<int>& m_node_number_vector; + + PUGS_INLINE + std::vector<unsigned int> + _sort(const std::vector<unsigned int>& node_list) + { + const auto min_id = std::min_element(node_list.begin(), node_list.end()); + const int shift = std::distance(node_list.begin(), min_id); + + std::vector<unsigned int> rotated_node_list(node_list.size()); + if (node_list[(shift + 1) % node_list.size()] > node_list[(shift + node_list.size() - 1) % node_list.size()]) { + for (size_t i = 0; i < node_list.size(); ++i) { + rotated_node_list[i] = node_list[(shift + node_list.size() - i) % node_list.size()]; + m_reversed = true; + } + } else { + for (size_t i = 0; i < node_list.size(); ++i) { + rotated_node_list[i] = node_list[(shift + i) % node_list.size()]; + } + } + + return rotated_node_list; + } + + public: + PUGS_INLINE + const bool& + reversed() const + { + return m_reversed; + } + + PUGS_INLINE + const std::vector<unsigned int>& + nodeIdList() const + { + return m_node_id_list; + } + + PUGS_INLINE + ConnectivityFace(const std::vector<unsigned int>& given_node_id_list, const std::vector<int>& node_number_vector) + : m_reversed(false), m_node_id_list(_sort(given_node_id_list)), m_node_number_vector(node_number_vector) + { + ; + } + + public: + bool + operator==(const ConnectivityFace& f) const + { + if (m_node_id_list.size() == f.nodeIdList().size()) { + for (size_t j = 0; j < m_node_id_list.size(); ++j) { + if (m_node_id_list[j] != f.nodeIdList()[j]) { + return false; + } + } + return true; + } + return false; + } + + PUGS_INLINE + bool + operator<(const ConnectivityFace& f) const + { + const size_t min_nb_nodes = std::min(f.m_node_id_list.size(), m_node_id_list.size()); + for (size_t i = 0; i < min_nb_nodes; ++i) { + if (m_node_id_list[i] < f.m_node_id_list[i]) + return true; + if (m_node_id_list[i] != f.m_node_id_list[i]) + return false; + } + return m_node_id_list.size() < f.m_node_id_list.size(); + } + + PUGS_INLINE + ConnectivityFace(const ConnectivityFace&) = default; + + PUGS_INLINE + ConnectivityFace() = delete; + + PUGS_INLINE + ~ConnectivityFace() = default; +}; + +#endif // CONNECTIVITY_BUILDER_BASE_HPP diff --git a/src/mesh/ConnectivityDispatcher.hpp b/src/mesh/ConnectivityDispatcher.hpp index 3de9c1c592a0dcc447104ce032c9d6efa9daceca..73ebc548d98a01e4999611927272206df4af1c23 100644 --- a/src/mesh/ConnectivityDispatcher.hpp +++ b/src/mesh/ConnectivityDispatcher.hpp @@ -3,7 +3,6 @@ #include <mesh/ItemValue.hpp> #include <mesh/ItemValueUtils.hpp> -#include <mesh/Mesh.hpp> #include <mesh/ConnectivityDescriptor.hpp> diff --git a/src/mesh/ConnectivityMatrix.hpp b/src/mesh/ConnectivityMatrix.hpp index 705dd8a3c6ff035e9c6a0be3cb4eac9cc77a70d2..576f7935fb11dce55ef20f9fdc5610bfbd27bbff 100644 --- a/src/mesh/ConnectivityMatrix.hpp +++ b/src/mesh/ConnectivityMatrix.hpp @@ -27,8 +27,6 @@ class ConnectivityMatrix entries() const { return encapsulate(m_host_matrix.entries); - // using DataType = typename decltype(m_host_matrix.entries)::value_type; - // return Array<DataType>(m_host_matrix.entries); } const auto& diff --git a/src/mesh/DiamondDualConnectivityBuilder.cpp b/src/mesh/DiamondDualConnectivityBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8bcbe9bad8e15cbef1dfa449c0d6defc115f126f --- /dev/null +++ b/src/mesh/DiamondDualConnectivityBuilder.cpp @@ -0,0 +1,495 @@ +#include <mesh/DiamondDualConnectivityBuilder.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityDescriptor.hpp> +#include <mesh/ConnectivityDispatcher.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/RefId.hpp> +#include <utils/Array.hpp> +#include <utils/Messenger.hpp> + +template <size_t Dimension> +void +DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connectivity<Dimension>& primal_connectivity, + ConnectivityDescriptor& diamond_descriptor) +{ + const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); + const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); + const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + + const size_t diamond_number_of_nodes = primal_number_of_cells + primal_number_of_nodes; + + diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes); + + const auto& primal_node_number = primal_connectivity.nodeNumber(); + + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + diamond_descriptor.node_number_vector[primal_node_id] = primal_node_number[primal_node_id]; + } + + const auto& primal_cell_number = primal_connectivity.cellNumber(); + + const size_t max_node_number = max(primal_node_number); + + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + diamond_descriptor.node_number_vector[primal_number_of_nodes + primal_cell_id] = + primal_cell_number[primal_cell_id] + max_node_number; + } + + const size_t diamond_number_of_cells = primal_number_of_faces; + diamond_descriptor.cell_number_vector.resize(diamond_number_of_cells); + + const auto& primal_face_number = primal_connectivity.faceNumber(); + for (FaceId i_primal_face = 0; i_primal_face < primal_number_of_faces; ++i_primal_face) { + diamond_descriptor.cell_number_vector[i_primal_face] = primal_face_number[i_primal_face]; + } + + if constexpr (Dimension == 3) { + const size_t number_of_edges = diamond_descriptor.edge_to_node_vector.size(); + diamond_descriptor.edge_number_vector.resize(number_of_edges); + for (size_t i_edge = 0; i_edge < number_of_edges; ++i_edge) { + diamond_descriptor.edge_number_vector[i_edge] = i_edge; + } + if (parallel::size() > 1) { + throw NotImplementedError("parallel edge numbering is undefined"); + } + } + + diamond_descriptor.cell_type_vector.resize(diamond_number_of_cells); + + const auto& primal_face_to_cell_matrix = primal_connectivity.faceToCellMatrix(); + + for (FaceId i_face = 0; i_face < primal_connectivity.numberOfFaces(); ++i_face) { + const size_t i_cell = i_face; + const auto& primal_face_cell_list = primal_face_to_cell_matrix[i_face]; + + if (primal_face_cell_list.size() == 1) { + diamond_descriptor.cell_type_vector[i_cell] = CellType::Triangle; + } else { + Assert(primal_face_cell_list.size() == 2); + diamond_descriptor.cell_type_vector[i_cell] = CellType::Quadrangle; + } + + if constexpr (Dimension == 3) { + if (primal_face_cell_list.size() == 1) { + diamond_descriptor.cell_type_vector[i_cell] = CellType::Pyramid; + } else { + Assert(primal_face_cell_list.size() == 2); + diamond_descriptor.cell_type_vector[i_cell] = CellType::Diamond; + } + } + } + + diamond_descriptor.cell_to_node_vector.resize(diamond_number_of_cells); + + const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); + const auto& primal_face_local_number_in_their_cells = primal_connectivity.faceLocalNumbersInTheirCells(); + const auto& cell_face_is_reversed = primal_connectivity.cellFaceIsReversed(); + for (FaceId i_face = 0; i_face < primal_connectivity.numberOfFaces(); ++i_face) { + const size_t& i_diamond_cell = i_face; + const auto& primal_face_cell_list = primal_face_to_cell_matrix[i_face]; + const auto& primal_face_node_list = primal_face_to_node_matrix[i_face]; + if (primal_face_cell_list.size() == 1) { + diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(primal_face_node_list.size() + 1); + + const CellId cell_id = primal_face_cell_list[0]; + const auto i_face_in_cell = primal_face_local_number_in_their_cells(i_face, 0); + + for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { + diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node] = primal_face_node_list[i_node]; + } + diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size()] = + primal_number_of_nodes + cell_id; + + if (cell_face_is_reversed(cell_id, i_face_in_cell)) { + if constexpr (Dimension == 2) { + std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0], + diamond_descriptor.cell_to_node_vector[i_diamond_cell][1]); + + } else { + for (size_t i_node = 0; i_node < primal_face_node_list.size() / 2; ++i_node) { + std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node], + diamond_descriptor + .cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() - 1 - i_node]); + } + } + } + } else { + Assert(primal_face_cell_list.size() == 2); + diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(primal_face_node_list.size() + 2); + + const CellId cell0_id = primal_face_cell_list[0]; + const CellId cell1_id = primal_face_cell_list[1]; + const auto i_face_in_cell0 = primal_face_local_number_in_their_cells(i_face, 0); + + if constexpr (Dimension == 2) { + Assert(primal_face_node_list.size() == 2); + diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_number_of_nodes + cell0_id; + diamond_descriptor.cell_to_node_vector[i_diamond_cell][1] = primal_face_node_list[0]; + diamond_descriptor.cell_to_node_vector[i_diamond_cell][2] = primal_number_of_nodes + cell1_id; + diamond_descriptor.cell_to_node_vector[i_diamond_cell][3] = primal_face_node_list[1]; + + if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { + std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][1], + diamond_descriptor.cell_to_node_vector[i_diamond_cell][3]); + } + } else { + diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_number_of_nodes + cell0_id; + for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { + diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node + 1] = primal_face_node_list[i_node]; + } + diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() + 1] = + primal_number_of_nodes + cell1_id; + + if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { + std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0], + diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() + 1]); + } + } + } + } +} + +template <> +void +DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor<1>(const Connectivity<1>& primal_connectivity, + ConnectivityDescriptor& diamond_descriptor) +{ + const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); + const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); + const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + + const size_t diamond_number_of_nodes = 2 * primal_number_of_nodes - primal_number_of_cells; + + diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes); + + const auto& primal_node_number = primal_connectivity.nodeNumber(); + + const size_t diamond_number_of_cells = primal_number_of_faces; + const size_t number_of_kept_nodes = 2 * (diamond_number_of_nodes - diamond_number_of_cells); + + const auto& primal_node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + size_t next_kept_node_id = 0; + + for (NodeId node_id = 0; node_id < primal_connectivity.numberOfNodes(); ++node_id) { + const auto& primal_node_cell_list = primal_node_to_cell_matrix[node_id]; + if (primal_node_cell_list.size() == 1) { + diamond_descriptor.node_number_vector[next_kept_node_id++] = primal_node_number[node_id]; + } + } + + if (number_of_kept_nodes != next_kept_node_id) { + throw UnexpectedError("unexpected number of kept node" + std::to_string(next_kept_node_id) + + " != " + std::to_string(number_of_kept_nodes)); + } + + diamond_descriptor.cell_number_vector.resize(diamond_number_of_cells); + + for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { + diamond_descriptor.cell_number_vector[primal_node_id] = primal_node_number[primal_node_id]; + } + + diamond_descriptor.cell_type_vector.resize(diamond_number_of_cells); + + for (NodeId node_id = 0; node_id < primal_connectivity.numberOfNodes(); ++node_id) { + const size_t i_cell = node_id; + + diamond_descriptor.cell_type_vector[i_cell] = CellType::Line; + } + + diamond_descriptor.cell_to_node_vector.resize(diamond_number_of_cells); + + ; + + const auto& primal_node_local_number_in_their_cells = primal_connectivity.nodeLocalNumbersInTheirCells(); + + { + size_t next_kept_node_id = 0; + for (NodeId i_node = 0; i_node < primal_connectivity.numberOfNodes(); ++i_node) { + const size_t& i_diamond_cell = i_node; + const auto& primal_node_cell_list = primal_node_to_cell_matrix[i_node]; + diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(2); + if (primal_node_cell_list.size() == 1) { + const auto i_node_in_cell = primal_node_local_number_in_their_cells(i_node, 0); + + diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node_in_cell] = next_kept_node_id++; + diamond_descriptor.cell_to_node_vector[i_diamond_cell][1 - i_node_in_cell] = + number_of_kept_nodes + primal_node_cell_list[0]; + } else { + diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = number_of_kept_nodes + primal_node_cell_list[0]; + diamond_descriptor.cell_to_node_vector[i_diamond_cell][1] = number_of_kept_nodes + primal_node_cell_list[1]; + } + } + } +} + +template <size_t Dimension> +void +DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivity& i_primal_connectivity) +{ + static_assert(Dimension <= 3, "invalid connectivity dimension"); + using ConnectivityType = Connectivity<Dimension>; + + const ConnectivityType& primal_connectivity = dynamic_cast<const ConnectivityType&>(i_primal_connectivity); + + ConnectivityDescriptor diamond_descriptor; + + this->_buildDiamondConnectivityDescriptor(primal_connectivity, diamond_descriptor); + + if constexpr (Dimension > 1) { + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<Dimension>(diamond_descriptor); + if constexpr (Dimension > 2) { + ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<Dimension>(diamond_descriptor); + } + } + + { + const std::unordered_map<unsigned int, NodeId> node_to_id_map = [&] { + std::unordered_map<unsigned int, NodeId> node_to_id_map; + for (size_t i_node = 0; i_node < diamond_descriptor.node_number_vector.size(); ++i_node) { + node_to_id_map[diamond_descriptor.node_number_vector[i_node]] = i_node; + } + return node_to_id_map; + }(); + + for (size_t i_node_list = 0; i_node_list < primal_connectivity.template numberOfRefItemList<ItemType::node>(); + ++i_node_list) { + const auto& primal_ref_node_list = primal_connectivity.template refItemList<ItemType::node>(i_node_list); + const auto& primal_node_list = primal_ref_node_list.list(); + + const std::vector<NodeId> diamond_node_list = [&]() { + std::vector<NodeId> diamond_node_list; + + for (size_t i_primal_node = 0; i_primal_node < primal_node_list.size(); ++i_primal_node) { + auto primal_node_id = primal_node_list[i_primal_node]; + const auto i_diamond_node = node_to_id_map.find(primal_connectivity.nodeNumber()[primal_node_id]); + if (i_diamond_node != node_to_id_map.end()) { + diamond_node_list.push_back(i_diamond_node->second); + } + } + + return diamond_node_list; + }(); + + if (parallel::allReduceOr(diamond_node_list.size() > 0)) { + Array<NodeId> node_array(diamond_node_list.size()); + for (size_t i = 0; i < diamond_node_list.size(); ++i) { + node_array[i] = diamond_node_list[i]; + } + diamond_descriptor.addRefItemList(RefNodeList{primal_ref_node_list.refId(), node_array}); + std::cout << "stored " << primal_ref_node_list.refId() << '\n'; + } + } + } + + if constexpr (Dimension > 1) { + const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); + + using Face = ConnectivityFace<Dimension>; + + const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { + std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; + for (FaceId l = 0; l < diamond_descriptor.face_to_node_vector.size(); ++l) { + const auto& node_vector = diamond_descriptor.face_to_node_vector[l]; + + face_to_id_map[Face(node_vector, diamond_descriptor.node_number_vector)] = l; + } + return face_to_id_map; + }(); + + for (size_t i_face_list = 0; i_face_list < primal_connectivity.template numberOfRefItemList<ItemType::face>(); + ++i_face_list) { + const auto& primal_ref_face_list = primal_connectivity.template refItemList<ItemType::face>(i_face_list); + const auto& primal_face_list = primal_ref_face_list.list(); + + const std::vector<FaceId> diamond_face_list = [&]() { + std::vector<FaceId> diamond_face_list; + diamond_face_list.reserve(primal_face_list.size()); + for (size_t i = 0; i < primal_face_list.size(); ++i) { + FaceId primal_face_id = primal_face_list[i]; + + const auto& primal_face_node_list = primal_face_to_node_matrix[primal_face_id]; + + const auto i_diamond_face = [&]() { + std::vector<unsigned int> node_list(primal_face_node_list.size()); + for (size_t i = 0; i < primal_face_node_list.size(); ++i) { + node_list[i] = primal_face_node_list[i]; + } + return face_to_id_map.find(Face(node_list, diamond_descriptor.node_number_vector)); + }(); + + if (i_diamond_face != face_to_id_map.end()) { + diamond_face_list.push_back(i_diamond_face->second); + } + } + return diamond_face_list; + }(); + + if (parallel::allReduceOr(diamond_face_list.size() > 0)) { + Array<FaceId> face_array(diamond_face_list.size()); + for (size_t i = 0; i < diamond_face_list.size(); ++i) { + face_array[i] = diamond_face_list[i]; + } + diamond_descriptor.addRefItemList(RefFaceList{primal_ref_face_list.refId(), face_array}); + std::cout << "stored " << primal_ref_face_list.refId() << '\n'; + } + } + } + + if constexpr (Dimension > 2) { + const auto& primal_edge_to_node_matrix = primal_connectivity.edgeToNodeMatrix(); + using Edge = ConnectivityFace<2>; + + const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { + std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; + for (EdgeId l = 0; l < diamond_descriptor.edge_to_node_vector.size(); ++l) { + const auto& node_vector = diamond_descriptor.edge_to_node_vector[l]; + edge_to_id_map[Edge(node_vector, diamond_descriptor.node_number_vector)] = l; + } + return edge_to_id_map; + }(); + + for (size_t i_edge_list = 0; i_edge_list < primal_connectivity.template numberOfRefItemList<ItemType::edge>(); + ++i_edge_list) { + const auto& primal_ref_edge_list = primal_connectivity.template refItemList<ItemType::edge>(i_edge_list); + const auto& primal_edge_list = primal_ref_edge_list.list(); + + const std::vector<EdgeId> diamond_edge_list = [&]() { + std::vector<EdgeId> diamond_edge_list; + diamond_edge_list.reserve(primal_edge_list.size()); + for (size_t i = 0; i < primal_edge_list.size(); ++i) { + EdgeId primal_edge_id = primal_edge_list[i]; + + const auto& primal_edge_node_list = primal_edge_to_node_matrix[primal_edge_id]; + + const auto i_diamond_edge = [&]() { + std::vector<unsigned int> node_list(primal_edge_node_list.size()); + for (size_t i = 0; i < primal_edge_node_list.size(); ++i) { + node_list[i] = primal_edge_node_list[i]; + } + return edge_to_id_map.find(Edge(node_list, diamond_descriptor.node_number_vector)); + }(); + + if (i_diamond_edge != edge_to_id_map.end()) { + diamond_edge_list.push_back(i_diamond_edge->second); + } + } + return diamond_edge_list; + }(); + + if (parallel::allReduceOr(diamond_edge_list.size() > 0)) { + Array<EdgeId> edge_array(diamond_edge_list.size()); + for (size_t i = 0; i < diamond_edge_list.size(); ++i) { + edge_array[i] = diamond_edge_list[i]; + } + diamond_descriptor.addRefItemList(RefEdgeList{primal_ref_edge_list.refId(), edge_array}); + std::cout << "stored " << primal_ref_edge_list.refId() << '\n'; + } + } + } + + const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); + const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + + diamond_descriptor.node_owner_vector.resize(diamond_descriptor.node_number_vector.size()); + + if constexpr (Dimension == 1) { + const auto& node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + const auto& primal_node_owner = primal_connectivity.nodeOwner(); + size_t next_kept_node_id = 0; + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + if (node_to_cell_matrix[primal_node_id].size() == 1) { + diamond_descriptor.node_owner_vector[next_kept_node_id++] = primal_node_owner[primal_node_id]; + } + } + const size_t number_of_kept_nodes = next_kept_node_id; + const auto& primal_cell_owner = primal_connectivity.cellOwner(); + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + diamond_descriptor.node_owner_vector[number_of_kept_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; + } + } else { + const auto& primal_node_owner = primal_connectivity.nodeOwner(); + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + diamond_descriptor.node_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; + } + const auto& primal_cell_owner = primal_connectivity.cellOwner(); + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + diamond_descriptor.node_owner_vector[primal_number_of_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; + } + } + + if constexpr (Dimension == 1) { + diamond_descriptor.cell_owner_vector.resize(diamond_descriptor.cell_number_vector.size()); + const auto& primal_node_owner = primal_connectivity.nodeOwner(); + for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { + diamond_descriptor.cell_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; + } + } else { + diamond_descriptor.cell_owner_vector.resize(diamond_descriptor.cell_number_vector.size()); + const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); + const auto& primal_face_owner = primal_connectivity.faceOwner(); + for (FaceId primal_face_id = 0; primal_face_id < primal_number_of_faces; ++primal_face_id) { + diamond_descriptor.cell_owner_vector[primal_face_id] = primal_face_owner[primal_face_id]; + } + } + + { + std::vector<int> face_cell_owner(diamond_descriptor.face_number_vector.size()); + std::fill(std::begin(face_cell_owner), std::end(face_cell_owner), parallel::size()); + + for (size_t i_cell = 0; i_cell < diamond_descriptor.cell_to_face_vector.size(); ++i_cell) { + const auto& cell_face_list = diamond_descriptor.cell_to_face_vector[i_cell]; + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + const size_t face_id = cell_face_list[i_face]; + face_cell_owner[face_id] = std::min(face_cell_owner[face_id], diamond_descriptor.cell_number_vector[i_cell]); + } + } + + diamond_descriptor.face_owner_vector.resize(face_cell_owner.size()); + for (size_t i_face = 0; i_face < face_cell_owner.size(); ++i_face) { + diamond_descriptor.face_owner_vector[i_face] = diamond_descriptor.cell_owner_vector[face_cell_owner[i_face]]; + } + } + + if constexpr (Dimension == 3) { + std::vector<int> edge_cell_owner(diamond_descriptor.edge_number_vector.size()); + std::fill(std::begin(edge_cell_owner), std::end(edge_cell_owner), parallel::size()); + + for (size_t i_cell = 0; i_cell < diamond_descriptor.cell_to_face_vector.size(); ++i_cell) { + const auto& cell_edge_list = diamond_descriptor.cell_to_edge_vector[i_cell]; + for (size_t i_edge = 0; i_edge < cell_edge_list.size(); ++i_edge) { + const size_t edge_id = cell_edge_list[i_edge]; + edge_cell_owner[edge_id] = std::min(edge_cell_owner[edge_id], diamond_descriptor.cell_number_vector[i_cell]); + } + } + + diamond_descriptor.edge_owner_vector.resize(edge_cell_owner.size()); + for (size_t i_edge = 0; i_edge < edge_cell_owner.size(); ++i_edge) { + diamond_descriptor.face_owner_vector[i_edge] = diamond_descriptor.cell_owner_vector[edge_cell_owner[i_edge]]; + } + } + + m_connectivity = ConnectivityType::build(diamond_descriptor); +} + +DiamondDualConnectivityBuilder::DiamondDualConnectivityBuilder(const IConnectivity& connectivity) +{ + switch (connectivity.dimension()) { + case 1: { + this->_buildDiamondConnectivityFrom<1>(connectivity); + break; + } + case 2: { + this->_buildDiamondConnectivityFrom<2>(connectivity); + break; + } + case 3: { + this->_buildDiamondConnectivityFrom<3>(connectivity); + break; + } + default: { + throw UnexpectedError("invalid connectivity dimension: " + std::to_string(connectivity.dimension())); + } + } +} diff --git a/src/mesh/DiamondDualConnectivityBuilder.hpp b/src/mesh/DiamondDualConnectivityBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..670372df9e53d3bfa8dd3f1b03545d9264b41dc4 --- /dev/null +++ b/src/mesh/DiamondDualConnectivityBuilder.hpp @@ -0,0 +1,26 @@ +#ifndef DIAMOND_DUAL_CONNECTIVITY_BUILDER_HPP +#define DIAMOND_DUAL_CONNECTIVITY_BUILDER_HPP + +#include <mesh/ConnectivityBuilderBase.hpp> + +#include <memory> + +template <size_t> +class Connectivity; +class ConnectivityDescriptor; + +class DiamondDualConnectivityBuilder : public ConnectivityBuilderBase +{ + private: + template <size_t Dimension> + void _buildDiamondConnectivityDescriptor(const Connectivity<Dimension>&, ConnectivityDescriptor&); + + template <size_t Dimension> + void _buildDiamondConnectivityFrom(const IConnectivity&); + + public: + DiamondDualConnectivityBuilder(const IConnectivity&); + ~DiamondDualConnectivityBuilder() = default; +}; + +#endif // DIAMOND_DUAL_CONNECTIVITY_BUILDER_HPP diff --git a/src/mesh/DiamondDualMeshBuilder.cpp b/src/mesh/DiamondDualMeshBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2218541b338e196a913b3c0859b882ad668d252e --- /dev/null +++ b/src/mesh/DiamondDualMeshBuilder.cpp @@ -0,0 +1,121 @@ +#include <mesh/DiamondDualMeshBuilder.hpp> + +#include <mesh/DiamondDualConnectivityBuilder.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityDescriptor.hpp> +#include <mesh/ConnectivityDispatcher.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> +#include <mesh/RefId.hpp> +#include <utils/Array.hpp> +#include <utils/Messenger.hpp> + +template <size_t Dimension> +void +DiamondDualMeshBuilder::_buildDualDiamondMeshFrom( + const Mesh<Connectivity<Dimension>>& primal_mesh, + const std::shared_ptr<const Connectivity<Dimension>>& p_diamond_connectivity) +{ + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<Connectivity<Dimension>>; + + const ConnectivityType& diamond_connectivity = *p_diamond_connectivity; + + NodeValue<TinyVector<Dimension>> diamond_xr{diamond_connectivity}; + + const NodeValue<const TinyVector<Dimension>> primal_xr = primal_mesh.xr(); + MeshData<Dimension>& primal_mesh_data = MeshDataManager::instance().getMeshData(primal_mesh); + const CellValue<const TinyVector<Dimension>> primal_xj = primal_mesh_data.xj(); + + NodeId i_node = 0; + for (; i_node < primal_mesh.numberOfNodes(); ++i_node) { + diamond_xr[i_node] = primal_xr[i_node]; + } + + for (CellId i_cell = 0; i_cell < primal_mesh.numberOfCells(); ++i_cell) { + diamond_xr[i_node++] = primal_xj[i_cell]; + } + + m_mesh = std::make_shared<MeshType>(p_diamond_connectivity, diamond_xr); +} + +template <> +void +DiamondDualMeshBuilder::_buildDualDiamondMeshFrom(const Mesh<Connectivity<1>>& primal_mesh, + const std::shared_ptr<const Connectivity<1>>& p_diamond_connectivity) +{ + using ConnectivityType = Connectivity<1>; + using MeshType = Mesh<Connectivity<1>>; + + const ConnectivityType& primal_connectivity = primal_mesh.connectivity(); + const auto& node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + + const ConnectivityType& diamond_connectivity = *p_diamond_connectivity; + + NodeValue<TinyVector<1>> diamond_xr{diamond_connectivity}; + + const NodeValue<const TinyVector<1>> primal_xr = primal_mesh.xr(); + MeshData<1>& primal_mesh_data = MeshDataManager::instance().getMeshData(primal_mesh); + const CellValue<const TinyVector<1>> primal_xj = primal_mesh_data.xj(); + + NodeId next_node_id = 0; + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + if (node_to_cell_matrix[primal_node_id].size() == 1) { + diamond_xr[next_node_id++] = primal_xr[primal_node_id]; + } + } + + for (CellId i_cell = 0; i_cell < primal_mesh.numberOfCells(); ++i_cell) { + diamond_xr[next_node_id++] = primal_xj[i_cell]; + } + + m_mesh = std::make_shared<MeshType>(p_diamond_connectivity, diamond_xr); +} + +DiamondDualMeshBuilder::DiamondDualMeshBuilder(const std::shared_ptr<const IMesh>& p_mesh) +{ + switch (p_mesh->dimension()) { + case 1: { + using ConnectivityType = Connectivity<1>; + using MeshType = Mesh<ConnectivityType>; + + std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); + DiamondDualConnectivityBuilder builder(mesh->connectivity()); + + std::shared_ptr p_diamond_connectivity = std::dynamic_pointer_cast<const ConnectivityType>(builder.connectivity()); + + this->_buildDualDiamondMeshFrom(*mesh, p_diamond_connectivity); + break; + } + case 2: { + using ConnectivityType = Connectivity<2>; + using MeshType = Mesh<ConnectivityType>; + + std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); + DiamondDualConnectivityBuilder builder(mesh->connectivity()); + + std::shared_ptr p_diamond_connectivity = std::dynamic_pointer_cast<const ConnectivityType>(builder.connectivity()); + + this->_buildDualDiamondMeshFrom(*mesh, p_diamond_connectivity); + break; + } + case 3: { + using ConnectivityType = Connectivity<3>; + using MeshType = Mesh<ConnectivityType>; + + std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); + DiamondDualConnectivityBuilder builder(mesh->connectivity()); + + std::shared_ptr p_diamond_connectivity = std::dynamic_pointer_cast<const ConnectivityType>(builder.connectivity()); + + this->_buildDualDiamondMeshFrom(*mesh, p_diamond_connectivity); + break; + } + default: { + throw UnexpectedError("invalid mesh dimension: " + std::to_string(p_mesh->dimension())); + } + } +} diff --git a/src/mesh/DiamondDualMeshBuilder.hpp b/src/mesh/DiamondDualMeshBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ded3cfb0f40ca4d1b1bd9dc06f7981391f9401c6 --- /dev/null +++ b/src/mesh/DiamondDualMeshBuilder.hpp @@ -0,0 +1,26 @@ +#ifndef DIAMOND_DUAL_MESH_BUILDER_HPP +#define DIAMOND_DUAL_MESH_BUILDER_HPP + +#include <mesh/MeshBuilderBase.hpp> + +#include <memory> + +template <size_t> +class Connectivity; + +template <typename ConnectivityType> +class Mesh; + +class DiamondDualMeshBuilder : public MeshBuilderBase +{ + private: + template <size_t Dimension> + void _buildDualDiamondMeshFrom(const Mesh<Connectivity<Dimension>>&, + const std::shared_ptr<const Connectivity<Dimension>>&); + + public: + DiamondDualMeshBuilder(const std::shared_ptr<const IMesh>&); + ~DiamondDualMeshBuilder() = default; +}; + +#endif // DIAMOND_DUAL_MESH_BUILDER_HPP diff --git a/src/mesh/GmshReader.cpp b/src/mesh/GmshReader.cpp index 629f32801454edcf3e25a3c68aeeaa972a4ea6ff..71284c13ed850c7ecd0da8c3bcab938ef93c5bf9 100644 --- a/src/mesh/GmshReader.cpp +++ b/src/mesh/GmshReader.cpp @@ -4,10 +4,10 @@ #include <mesh/CellType.hpp> #include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityBuilderBase.hpp> #include <mesh/ConnectivityDispatcher.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> -#include <mesh/MeshData.hpp> #include <mesh/RefItemList.hpp> #include <utils/ArrayUtils.hpp> #include <utils/Exceptions.hpp> @@ -23,217 +23,449 @@ #include <sstream> #include <unordered_map> -template <int Dimension> -void -GmshReader::_dispatch() +template <size_t Dimension> +class GmshConnectivityBuilder : public ConnectivityBuilderBase +{ + public: + GmshConnectivityBuilder(const GmshReader::GmshData& gmsh_data, const size_t nb_cells); +}; + +template <> +GmshConnectivityBuilder<1>::GmshConnectivityBuilder(const GmshReader::GmshData& gmsh_data, const size_t nb_cells) { - using ConnectivityType = Connectivity<Dimension>; - using Rd = TinyVector<Dimension>; - using MeshType = Mesh<ConnectivityType>; - - if (not m_mesh) { - ConnectivityDescriptor descriptor; - std::shared_ptr connectivity = ConnectivityType::build(descriptor); - NodeValue<Rd> xr; - m_mesh = std::make_shared<MeshType>(connectivity, xr); + ConnectivityDescriptor descriptor; + + descriptor.node_number_vector = gmsh_data.__verticesNumbers; + descriptor.cell_type_vector.resize(nb_cells); + descriptor.cell_number_vector.resize(nb_cells); + descriptor.cell_to_node_vector.resize(nb_cells); + + for (size_t j = 0; j < nb_cells; ++j) { + descriptor.cell_to_node_vector[j].resize(2); + for (int r = 0; r < 2; ++r) { + descriptor.cell_to_node_vector[j][r] = gmsh_data.__edges[j][r]; + } + descriptor.cell_type_vector[j] = CellType::Line; + descriptor.cell_number_vector[j] = gmsh_data.__edges_number[j]; } - const MeshType& mesh = static_cast<const MeshType&>(*m_mesh); - ConnectivityDispatcher<Dimension> dispatcher(mesh.connectivity()); + std::map<unsigned int, std::vector<unsigned int>> ref_points_map; + for (unsigned int r = 0; r < gmsh_data.__points.size(); ++r) { + const unsigned int point_number = gmsh_data.__points[r]; + const unsigned int& ref = gmsh_data.__points_ref[r]; + ref_points_map[ref].push_back(point_number); + } - std::shared_ptr dispatched_connectivity = dispatcher.dispatchedConnectivity(); - NodeValue<Rd> dispatched_xr = dispatcher.dispatch(mesh.xr()); + for (const auto& ref_point_list : ref_points_map) { + Array<NodeId> point_list(ref_point_list.second.size()); + for (size_t j = 0; j < ref_point_list.second.size(); ++j) { + point_list[j] = ref_point_list.second[j]; + } + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_point_list.first); + descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); + } - m_mesh = std::make_shared<MeshType>(dispatched_connectivity, dispatched_xr); -} + descriptor.cell_owner_vector.resize(nb_cells); + std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); -template <size_t Dimension> -class ConnectivityFace; + descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); + std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + + m_connectivity = Connectivity1D::build(descriptor); +} template <> -class ConnectivityFace<2> +GmshConnectivityBuilder<2>::GmshConnectivityBuilder(const GmshReader::GmshData& gmsh_data, const size_t nb_cells) { - public: - friend struct Hash; - struct Hash - { - size_t - operator()(const ConnectivityFace& f) const - { - size_t hash = 0; - hash ^= std::hash<unsigned int>()(f.m_node0_id); - hash ^= std::hash<unsigned int>()(f.m_node1_id) >> 1; - return hash; + ConnectivityDescriptor descriptor; + + descriptor.node_number_vector = gmsh_data.__verticesNumbers; + descriptor.cell_type_vector.resize(nb_cells); + descriptor.cell_number_vector.resize(nb_cells); + descriptor.cell_to_node_vector.resize(nb_cells); + + const size_t nb_triangles = gmsh_data.__triangles.size(); + for (size_t j = 0; j < nb_triangles; ++j) { + descriptor.cell_to_node_vector[j].resize(3); + for (int r = 0; r < 3; ++r) { + descriptor.cell_to_node_vector[j][r] = gmsh_data.__triangles[j][r]; } - }; + descriptor.cell_type_vector[j] = CellType::Triangle; + descriptor.cell_number_vector[j] = gmsh_data.__triangles_number[j]; + } - private: - const std::vector<int>& m_node_number_vector; + const size_t nb_quadrangles = gmsh_data.__quadrangles.size(); + for (size_t j = 0; j < nb_quadrangles; ++j) { + const size_t jq = j + nb_triangles; + descriptor.cell_to_node_vector[jq].resize(4); + for (int r = 0; r < 4; ++r) { + descriptor.cell_to_node_vector[jq][r] = gmsh_data.__quadrangles[j][r]; + } + descriptor.cell_type_vector[jq] = CellType::Quadrangle; + descriptor.cell_number_vector[jq] = gmsh_data.__quadrangles_number[j]; + } - unsigned int m_node0_id; - unsigned int m_node1_id; + std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; + for (unsigned int r = 0; r < gmsh_data.__triangles_ref.size(); ++r) { + const unsigned int elem_number = gmsh_data.__triangles_ref[r]; + const unsigned int& ref = gmsh_data.__triangles_ref[r]; + ref_cells_map[ref].push_back(elem_number); + } - bool m_reversed; + for (unsigned int j = 0; j < gmsh_data.__quadrangles_ref.size(); ++j) { + const size_t elem_number = nb_triangles + j; + const unsigned int& ref = gmsh_data.__quadrangles_ref[j]; + ref_cells_map[ref].push_back(elem_number); + } - public: - std::vector<unsigned int> - nodeIdList() const - { - return {m_node0_id, m_node1_id}; + for (const auto& ref_cell_list : ref_cells_map) { + Array<CellId> cell_list(ref_cell_list.second.size()); + for (size_t j = 0; j < ref_cell_list.second.size(); ++j) { + cell_list[j] = ref_cell_list.second[j]; + } + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_cell_list.first); + descriptor.addRefItemList(RefCellList(physical_ref_id.refId(), cell_list)); } - bool - reversed() const - { - return m_reversed; + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<2>(descriptor); + + using Face = ConnectivityFace<2>; + const auto& node_number_vector = descriptor.node_number_vector; + const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { + std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; + for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { + const auto& node_vector = descriptor.face_to_node_vector[l]; + face_to_id_map[Face(node_vector, node_number_vector)] = l; + } + return face_to_id_map; + }(); + + std::unordered_map<int, FaceId> face_number_id_map = [&] { + std::unordered_map<int, FaceId> face_number_id_map; + for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { + face_number_id_map[descriptor.face_number_vector[l]] = l; + } + Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); + return face_number_id_map; + }(); + + std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; + for (unsigned int e = 0; e < gmsh_data.__edges.size(); ++e) { + const unsigned int edge_id = [&] { + auto i = face_to_id_map.find(Face({gmsh_data.__edges[e][0], gmsh_data.__edges[e][1]}, node_number_vector)); + if (i == face_to_id_map.end()) { + std::stringstream error_msg; + error_msg << "face " << gmsh_data.__edges[e][0] << " not found"; + throw NormalError(error_msg.str()); + } + return i->second; + }(); + const unsigned int& ref = gmsh_data.__edges_ref[e]; + ref_faces_map[ref].push_back(edge_id); + + if (descriptor.face_number_vector[edge_id] != gmsh_data.__edges_number[e]) { + if (auto i_face = face_number_id_map.find(gmsh_data.__edges_number[e]); i_face != face_number_id_map.end()) { + const int other_edge_id = i_face->second; + std::swap(descriptor.face_number_vector[edge_id], descriptor.face_number_vector[other_edge_id]); + + face_number_id_map.erase(descriptor.face_number_vector[edge_id]); + face_number_id_map.erase(descriptor.face_number_vector[other_edge_id]); + + face_number_id_map[descriptor.face_number_vector[edge_id]] = edge_id; + face_number_id_map[descriptor.face_number_vector[other_edge_id]] = other_edge_id; + } else { + face_number_id_map.erase(descriptor.face_number_vector[edge_id]); + descriptor.face_number_vector[edge_id] = gmsh_data.__edges_number[e]; + face_number_id_map[descriptor.face_number_vector[edge_id]] = edge_id; + } + } } - PUGS_INLINE - bool - operator==(const ConnectivityFace& f) const - { - return ((m_node0_id == f.m_node0_id) and (m_node1_id == f.m_node1_id)); + for (const auto& ref_face_list : ref_faces_map) { + Array<FaceId> face_list(ref_face_list.second.size()); + for (size_t j = 0; j < ref_face_list.second.size(); ++j) { + face_list[j] = ref_face_list.second[j]; + } + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_face_list.first); + descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list}); } - PUGS_INLINE - bool - operator<(const ConnectivityFace& f) const - { - return ((m_node_number_vector[m_node0_id] < m_node_number_vector[f.m_node0_id]) or - ((m_node_number_vector[m_node0_id] == m_node_number_vector[f.m_node0_id]) and - (m_node_number_vector[m_node1_id] < m_node_number_vector[f.m_node1_id]))); + std::map<unsigned int, std::vector<unsigned int>> ref_points_map; + for (unsigned int r = 0; r < gmsh_data.__points.size(); ++r) { + const unsigned int point_number = gmsh_data.__points[r]; + const unsigned int& ref = gmsh_data.__points_ref[r]; + ref_points_map[ref].push_back(point_number); } - PUGS_INLINE - ConnectivityFace(const std::vector<unsigned int>& node_id_list, const std::vector<int>& node_number_vector) - : m_node_number_vector(node_number_vector) - { - Assert(node_id_list.size() == 2); - - if (m_node_number_vector[node_id_list[0]] < m_node_number_vector[node_id_list[1]]) { - m_node0_id = node_id_list[0]; - m_node1_id = node_id_list[1]; - m_reversed = false; - } else { - m_node0_id = node_id_list[1]; - m_node1_id = node_id_list[0]; - m_reversed = true; + for (const auto& ref_point_list : ref_points_map) { + Array<NodeId> point_list(ref_point_list.second.size()); + for (size_t j = 0; j < ref_point_list.second.size(); ++j) { + point_list[j] = ref_point_list.second[j]; } + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_point_list.first); + descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); } - PUGS_INLINE - ConnectivityFace(const ConnectivityFace&) = default; + descriptor.cell_owner_vector.resize(nb_cells); + std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - PUGS_INLINE - ~ConnectivityFace() = default; -}; + descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); + std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); + + descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); + std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + + m_connectivity = Connectivity2D::build(descriptor); +} template <> -class ConnectivityFace<3> +GmshConnectivityBuilder<3>::GmshConnectivityBuilder(const GmshReader::GmshData& gmsh_data, const size_t nb_cells) { - private: - friend class GmshReader; - friend struct Hash; - struct Hash - { - size_t - operator()(const ConnectivityFace& f) const - { - size_t hash = 0; - for (size_t i = 0; i < f.m_node_id_list.size(); ++i) { - hash ^= std::hash<unsigned int>()(f.m_node_id_list[i]) >> i; - } - return hash; - } - }; + ConnectivityDescriptor descriptor; - private: - bool m_reversed; - std::vector<NodeId::base_type> m_node_id_list; - const std::vector<int>& m_node_number_vector; + descriptor.node_number_vector = gmsh_data.__verticesNumbers; + descriptor.cell_type_vector.resize(nb_cells); + descriptor.cell_number_vector.resize(nb_cells); + descriptor.cell_to_node_vector.resize(nb_cells); - PUGS_INLINE - std::vector<unsigned int> - _sort(const std::vector<unsigned int>& node_list) - { - const auto min_id = std::min_element(node_list.begin(), node_list.end()); - const int shift = std::distance(node_list.begin(), min_id); - - std::vector<unsigned int> rotated_node_list(node_list.size()); - if (node_list[(shift + 1) % node_list.size()] > node_list[(shift + node_list.size() - 1) % node_list.size()]) { - for (size_t i = 0; i < node_list.size(); ++i) { - rotated_node_list[i] = node_list[(shift + node_list.size() - i) % node_list.size()]; - m_reversed = true; - } - } else { - for (size_t i = 0; i < node_list.size(); ++i) { - rotated_node_list[i] = node_list[(shift + i) % node_list.size()]; - } + const size_t nb_tetrahedra = gmsh_data.__tetrahedra.size(); + for (size_t j = 0; j < nb_tetrahedra; ++j) { + descriptor.cell_to_node_vector[j].resize(4); + for (int r = 0; r < 4; ++r) { + descriptor.cell_to_node_vector[j][r] = gmsh_data.__tetrahedra[j][r]; } + descriptor.cell_type_vector[j] = CellType::Tetrahedron; + descriptor.cell_number_vector[j] = gmsh_data.__tetrahedra_number[j]; + } + const size_t nb_hexahedra = gmsh_data.__hexahedra.size(); + for (size_t j = 0; j < nb_hexahedra; ++j) { + const size_t jh = nb_tetrahedra + j; + descriptor.cell_to_node_vector[jh].resize(8); + for (int r = 0; r < 8; ++r) { + descriptor.cell_to_node_vector[jh][r] = gmsh_data.__hexahedra[j][r]; + } + descriptor.cell_type_vector[jh] = CellType::Hexahedron; + descriptor.cell_number_vector[jh] = gmsh_data.__hexahedra_number[j]; + } - return rotated_node_list; + std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; + for (unsigned int r = 0; r < gmsh_data.__tetrahedra_ref.size(); ++r) { + const unsigned int elem_number = gmsh_data.__tetrahedra_ref[r]; + const unsigned int& ref = gmsh_data.__tetrahedra_ref[r]; + ref_cells_map[ref].push_back(elem_number); } - public: - PUGS_INLINE - const bool& - reversed() const - { - return m_reversed; + for (unsigned int j = 0; j < gmsh_data.__hexahedra_ref.size(); ++j) { + const size_t elem_number = nb_tetrahedra + j; + const unsigned int& ref = gmsh_data.__hexahedra_ref[j]; + ref_cells_map[ref].push_back(elem_number); } - PUGS_INLINE - const std::vector<unsigned int>& - nodeIdList() const - { - return m_node_id_list; + for (const auto& ref_cell_list : ref_cells_map) { + Array<CellId> cell_list(ref_cell_list.second.size()); + for (size_t j = 0; j < ref_cell_list.second.size(); ++j) { + cell_list[j] = ref_cell_list.second[j]; + } + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_cell_list.first); + descriptor.addRefItemList(RefCellList(physical_ref_id.refId(), cell_list)); } - PUGS_INLINE - ConnectivityFace(const std::vector<unsigned int>& given_node_id_list, const std::vector<int>& node_number_vector) - : m_reversed(false), m_node_id_list(_sort(given_node_id_list)), m_node_number_vector(node_number_vector) + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<3>(descriptor); + + const auto& node_number_vector = descriptor.node_number_vector; + { - ; + using Face = ConnectivityFace<3>; + const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { + std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; + for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { + const auto& node_vector = descriptor.face_to_node_vector[l]; + face_to_id_map[Face(node_vector, node_number_vector)] = l; + } + return face_to_id_map; + }(); + + std::unordered_map<int, FaceId> face_number_id_map = [&] { + std::unordered_map<int, FaceId> face_number_id_map; + for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { + face_number_id_map[descriptor.face_number_vector[l]] = l; + } + Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); + return face_number_id_map; + }(); + + std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; + for (unsigned int f = 0; f < gmsh_data.__triangles.size(); ++f) { + const unsigned int face_id = [&] { + auto i = face_to_id_map.find( + Face({gmsh_data.__triangles[f][0], gmsh_data.__triangles[f][1], gmsh_data.__triangles[f][2]}, + node_number_vector)); + if (i == face_to_id_map.end()) { + throw NormalError("face not found"); + } + return i->second; + }(); + + const unsigned int& ref = gmsh_data.__triangles_ref[f]; + ref_faces_map[ref].push_back(face_id); + + if (descriptor.face_number_vector[face_id] != gmsh_data.__quadrangles_number[f]) { + if (auto i_face = face_number_id_map.find(gmsh_data.__quadrangles_number[f]); + i_face != face_number_id_map.end()) { + const int other_face_id = i_face->second; + std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); + + face_number_id_map.erase(descriptor.face_number_vector[face_id]); + face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); + + face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; + face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; + } else { + face_number_id_map.erase(descriptor.face_number_vector[face_id]); + descriptor.face_number_vector[face_id] = gmsh_data.__quadrangles_number[f]; + face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; + } + } + } + + for (unsigned int f = 0; f < gmsh_data.__quadrangles.size(); ++f) { + const unsigned int face_id = [&] { + auto i = face_to_id_map.find(Face({gmsh_data.__quadrangles[f][0], gmsh_data.__quadrangles[f][1], + gmsh_data.__quadrangles[f][2], gmsh_data.__quadrangles[f][3]}, + node_number_vector)); + if (i == face_to_id_map.end()) { + throw NormalError("face not found"); + } + return i->second; + }(); + + const unsigned int& ref = gmsh_data.__quadrangles_ref[f]; + ref_faces_map[ref].push_back(face_id); + + if (descriptor.face_number_vector[face_id] != gmsh_data.__quadrangles_number[f]) { + if (auto i_face = face_number_id_map.find(gmsh_data.__quadrangles_number[f]); + i_face != face_number_id_map.end()) { + const int other_face_id = i_face->second; + std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); + + face_number_id_map.erase(descriptor.face_number_vector[face_id]); + face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); + + face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; + face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; + } else { + face_number_id_map.erase(descriptor.face_number_vector[face_id]); + descriptor.face_number_vector[face_id] = gmsh_data.__quadrangles_number[f]; + face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; + } + } + } + + for (const auto& ref_face_list : ref_faces_map) { + Array<FaceId> face_list(ref_face_list.second.size()); + for (size_t j = 0; j < ref_face_list.second.size(); ++j) { + face_list[j] = ref_face_list.second[j]; + } + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_face_list.first); + descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list}); + } } - public: - bool - operator==(const ConnectivityFace& f) const + ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<3>(descriptor); + { - if (m_node_id_list.size() == f.nodeIdList().size()) { - for (size_t j = 0; j < m_node_id_list.size(); ++j) { - if (m_node_id_list[j] != f.nodeIdList()[j]) { - return false; + using Edge = ConnectivityFace<2>; + const auto& node_number_vector = descriptor.node_number_vector; + const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { + std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; + for (EdgeId l = 0; l < descriptor.edge_to_node_vector.size(); ++l) { + const auto& node_vector = descriptor.edge_to_node_vector[l]; + edge_to_id_map[Edge(node_vector, node_number_vector)] = l; + } + return edge_to_id_map; + }(); + + std::unordered_map<int, EdgeId> edge_number_id_map = [&] { + std::unordered_map<int, EdgeId> edge_number_id_map; + for (size_t l = 0; l < descriptor.edge_number_vector.size(); ++l) { + edge_number_id_map[descriptor.edge_number_vector[l]] = l; + } + Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size()); + return edge_number_id_map; + }(); + + std::map<unsigned int, std::vector<unsigned int>> ref_edges_map; + for (unsigned int e = 0; e < gmsh_data.__edges.size(); ++e) { + const unsigned int edge_id = [&] { + auto i = edge_to_id_map.find(Edge({gmsh_data.__edges[e][0], gmsh_data.__edges[e][1]}, node_number_vector)); + if (i == edge_to_id_map.end()) { + std::stringstream error_msg; + error_msg << "edge " << gmsh_data.__edges[e][0] << " not found"; + throw NormalError(error_msg.str()); + } + return i->second; + }(); + const unsigned int& ref = gmsh_data.__edges_ref[e]; + ref_edges_map[ref].push_back(edge_id); + + if (descriptor.edge_number_vector[edge_id] != gmsh_data.__edges_number[e]) { + if (auto i_edge = edge_number_id_map.find(gmsh_data.__edges_number[e]); i_edge != edge_number_id_map.end()) { + const int other_edge_id = i_edge->second; + std::swap(descriptor.edge_number_vector[edge_id], descriptor.edge_number_vector[other_edge_id]); + + edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); + edge_number_id_map.erase(descriptor.edge_number_vector[other_edge_id]); + + edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; + edge_number_id_map[descriptor.edge_number_vector[other_edge_id]] = other_edge_id; + } else { + edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); + descriptor.edge_number_vector[edge_id] = gmsh_data.__edges_number[e]; + edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; } } - return true; } - return false; + + for (const auto& ref_edge_list : ref_edges_map) { + Array<EdgeId> edge_list(ref_edge_list.second.size()); + for (size_t j = 0; j < ref_edge_list.second.size(); ++j) { + edge_list[j] = ref_edge_list.second[j]; + } + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_edge_list.first); + descriptor.addRefItemList(RefEdgeList{physical_ref_id.refId(), edge_list}); + } } - PUGS_INLINE - bool - operator<(const ConnectivityFace& f) const - { - const size_t min_nb_nodes = std::min(f.m_node_id_list.size(), m_node_id_list.size()); - for (size_t i = 0; i < min_nb_nodes; ++i) { - if (m_node_id_list[i] < f.m_node_id_list[i]) - return true; - if (m_node_id_list[i] != f.m_node_id_list[i]) - return false; + std::map<unsigned int, std::vector<unsigned int>> ref_points_map; + for (unsigned int r = 0; r < gmsh_data.__points.size(); ++r) { + const unsigned int point_number = gmsh_data.__points[r]; + const unsigned int& ref = gmsh_data.__points_ref[r]; + ref_points_map[ref].push_back(point_number); + } + + for (const auto& ref_point_list : ref_points_map) { + Array<NodeId> point_list(ref_point_list.second.size()); + for (size_t j = 0; j < ref_point_list.second.size(); ++j) { + point_list[j] = ref_point_list.second[j]; } - return m_node_id_list.size() < f.m_node_id_list.size(); + const GmshReader::PhysicalRefId& physical_ref_id = gmsh_data.m_physical_ref_map.at(ref_point_list.first); + descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); } - PUGS_INLINE - ConnectivityFace(const ConnectivityFace&) = default; + descriptor.cell_owner_vector.resize(nb_cells); + std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - PUGS_INLINE - ConnectivityFace() = delete; + descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); + std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); - PUGS_INLINE - ~ConnectivityFace() = default; -}; + descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size()); + std::fill(descriptor.edge_owner_vector.begin(), descriptor.edge_owner_vector.end(), parallel::rank()); + + descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); + std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + + m_connectivity = Connectivity3D::build(descriptor); +} GmshReader::GmshReader(const std::string& filename) : m_filename(filename) { @@ -318,7 +550,6 @@ GmshReader::GmshReader(const std::string& filename) : m_filename(filename) throw NormalError("Cannot read Gmsh format '" + std::to_string(fileVersion) + "'"); } int fileType = this->_getInteger(); - __binary = (fileType == 1); if ((fileType < 0) or (fileType > 1)) { throw NormalError("Cannot read Gmsh file type '" + std::to_string(fileType) + "'"); } @@ -328,10 +559,6 @@ GmshReader::GmshReader(const std::string& filename) : m_filename(filename) throw NormalError("Data size not supported '" + std::to_string(dataSize) + "'"); } - if (__binary) { - throw NotImplementedError("cannot read binary files"); - } - kw = this->__nextKeyword(); if (kw.second != ENDMESHFORMAT) { throw NormalError("reading file '" + m_filename + "': expecting $EndMeshFormat, '" + kw.first + "' was found"); @@ -401,71 +628,18 @@ GmshReader::__readVertices() throw NormalError("reading file '" + this->m_filename + "': number of vertices is negative"); } - __verticesNumbers.resize(numberOfVerices); - __vertices = Array<R3>(numberOfVerices); + m_mesh_data.__verticesNumbers.resize(numberOfVerices); + m_mesh_data.__vertices = Array<R3>(numberOfVerices); - if (not __binary) { - for (int i = 0; i < numberOfVerices; ++i) { - __verticesNumbers[i] = this->_getInteger(); - const double x = this->_getReal(); - const double y = this->_getReal(); - const double z = this->_getReal(); - __vertices[i] = TinyVector<3, double>(x, y, z); - } - } else { - throw NotImplementedError("cannot read binary format"); + for (int i = 0; i < numberOfVerices; ++i) { + m_mesh_data.__verticesNumbers[i] = this->_getInteger(); + const double x = this->_getReal(); + const double y = this->_getReal(); + const double z = this->_getReal(); + m_mesh_data.__vertices[i] = TinyVector<3, double>(x, y, z); } } -// void -// GmshReader::__readElements1() -// { -// const int numberOfElements = this->_getInteger(); -// std::cout << "- Number Of Elements: " << numberOfElements << '\n'; -// if (numberOfElements<0) { -// throw ErrorHandler(__FILE__,__LINE__, -// "reading file '"+m_filename -// +"': number of elements is negative", -// ErrorHandler::normal); -// } - -// __elementType.resize(numberOfElements); -// __references.resize(numberOfElements); -// __elementVertices.resize(numberOfElements); - -// for (int i=0; i<numberOfElements; ++i) { -// this->_getInteger(); // drops element number -// const int elementType = this->_getInteger()-1; - -// if ((elementType < 0) or (elementType > 14)) { -// throw ErrorHandler(__FILE__,__LINE__, -// "reading file '"+m_filename -// +"': unknown element type -// '"+std::to_string(elementType)+"'", ErrorHandler::normal); -// } -// __elementType[i] = elementType; -// __references[i] = this->_getInteger(); // physical reference -// this->_getInteger(); // drops entity reference - -// const int numberOfVertices = this->_getInteger(); -// if (numberOfVertices != __numberOfPrimitiveNodes[elementType]) { -// std::stringstream errorMsg; -// errorMsg << "reading file '" <<m_filename -// << "':number of vertices (" << numberOfVertices -// << ") does not match expected (" -// << __numberOfPrimitiveNodes[elementType] << ")" << std::ends; - -// throw ErrorHandler(__FILE__,__LINE__, -// errorMsg.str(), -// ErrorHandler::normal); -// } -// __elementVertices[i].resize(numberOfVertices); -// for (int j=0; j<numberOfVertices; ++j) { -// __elementVertices[i][j] = this->_getInteger(); -// } -// } -// } - void GmshReader::__readElements2_2() { @@ -475,96 +649,31 @@ GmshReader::__readElements2_2() throw NormalError("reading file '" + m_filename + "': number of elements is negative"); } - __elementNumber.resize(numberOfElements); - __elementType.resize(numberOfElements); - __references.resize(numberOfElements); - __elementVertices.resize(numberOfElements); - - if (not __binary) { - for (int i = 0; i < numberOfElements; ++i) { - __elementNumber[i] = this->_getInteger(); - const int elementType = this->_getInteger() - 1; + m_mesh_data.__elementNumber.resize(numberOfElements); + m_mesh_data.__elementType.resize(numberOfElements); + m_mesh_data.__references.resize(numberOfElements); + m_mesh_data.__elementVertices.resize(numberOfElements); - if ((elementType < 0) or (elementType > 14)) { - throw NormalError("reading file '" + m_filename + "': unknown element type '" + std::to_string(elementType) + - "'"); - } - __elementType[i] = elementType; - const int numberOfTags = this->_getInteger(); - __references[i] = this->_getInteger(); // physical reference - for (int tag = 1; tag < numberOfTags; ++tag) { - this->_getInteger(); // drops remaining tags - } + for (int i = 0; i < numberOfElements; ++i) { + m_mesh_data.__elementNumber[i] = this->_getInteger(); + const int elementType = this->_getInteger() - 1; - const int numberOfVertices = __numberOfPrimitiveNodes[elementType]; - __elementVertices[i].resize(numberOfVertices); - for (int j = 0; j < numberOfVertices; ++j) { - __elementVertices[i][j] = this->_getInteger(); - } + if ((elementType < 0) or (elementType > 14)) { + throw NormalError("reading file '" + m_filename + "': unknown element type '" + std::to_string(elementType) + + "'"); + } + m_mesh_data.__elementType[i] = elementType; + const int numberOfTags = this->_getInteger(); + m_mesh_data.__references[i] = this->_getInteger(); // physical reference + for (int tag = 1; tag < numberOfTags; ++tag) { + this->_getInteger(); // drops remaining tags } - } else { - // fseek(__ifh,1L,SEEK_CUR); - // int i=0; - // for (;i<numberOfElements;) { - // int elementType = 0; - // fread(reinterpret_cast<char*>(&elementType),sizeof(int),1,__ifh); - // if (__convertEndian) { - // invertEndianess(elementType); - // } - // --elementType; - - // if ((elementType < 0) or (elementType > 14)) { - // throw ErrorHandler(__FILE__,__LINE__, - // "reading file '"+m_filename - // +"': unknown element type - // '"+std::to_string(elementType)+"'", - // ErrorHandler::normal); - // } - - // int elementTypeNumber = 0; - // fread(reinterpret_cast<char*>(&elementTypeNumber),sizeof(int),1,__ifh); - // if (__convertEndian) { - // invertEndianess(elementTypeNumber); - // } - - // int numberOfTags = 0; - // fread(reinterpret_cast<char*>(&numberOfTags),sizeof(int),1,__ifh); - // if (__convertEndian) { - // invertEndianess(numberOfTags); - // } - - // for (int k=0; k<elementTypeNumber; ++k) { - // __elementType[i] = elementType; - - // int elementNumber = 0; - // fread(reinterpret_cast<char*>(&elementNumber),sizeof(int),1,__ifh); - - // int reference = 0; - // fread(reinterpret_cast<char*>(&reference),sizeof(int),1,__ifh); - - // __references[i] = reference; // physical reference - // for (int tag=1; tag<numberOfTags; ++tag) { - // int t; - // fread(reinterpret_cast<char*>(&t),sizeof(int),1,__ifh); - // } - - // const int numberOfVertices = __numberOfPrimitiveNodes[elementType]; - // __elementVertices[i].resize(numberOfVertices); - // fread(reinterpret_cast<char*>(&(__elementVertices[i][0])),sizeof(int),numberOfVertices,__ifh); - // ++i; - // } - // } - // if (__convertEndian) { - // for (size_t i=0; i<__references.size(); ++i) { - // invertEndianess(__references[i]); - // } - // for (size_t i=0; i<__elementVertices.size(); ++i) { - // for (size_t j=0; j<__elementVertices[i].size(); ++i) { - // invertEndianess(__elementVertices[i][j]); - // } - // } - // } + const int numberOfVertices = __numberOfPrimitiveNodes[elementType]; + m_mesh_data.__elementVertices[i].resize(numberOfVertices); + for (int j = 0; j < numberOfVertices; ++j) { + m_mesh_data.__elementVertices[i][j] = this->_getInteger(); + } } } @@ -581,303 +690,266 @@ GmshReader::__readPhysicalNames2_2() PhysicalRefId physical_ref_id(physical_dimension, RefId(physical_number, physical_name)); - if (auto i_searched_physical_ref_id = m_physical_ref_map.find(physical_number); - i_searched_physical_ref_id != m_physical_ref_map.end()) { + if (auto i_searched_physical_ref_id = m_mesh_data.m_physical_ref_map.find(physical_number); + i_searched_physical_ref_id != m_mesh_data.m_physical_ref_map.end()) { std::stringstream os; os << "Physical reference id '" << physical_ref_id << "' already defined as '" << i_searched_physical_ref_id->second << "'!"; throw NormalError(os.str()); } - m_physical_ref_map[physical_number] = physical_ref_id; + m_mesh_data.m_physical_ref_map[physical_number] = physical_ref_id; } } -template <size_t Dimension> -void -GmshReader::__computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& descriptor) -{ - static_assert((Dimension == 2) or (Dimension == 3), "Invalid dimension to compute cell-face connectivities"); - using CellFaceInfo = std::tuple<CellId, unsigned short, bool>; - using Face = ConnectivityFace<Dimension>; - - const auto& node_number_vector = descriptor.node_number_vector; - Array<unsigned short> cell_nb_faces(descriptor.cell_to_node_vector.size()); - std::map<Face, std::vector<CellFaceInfo>> face_cells_map; - for (CellId j = 0; j < descriptor.cell_to_node_vector.size(); ++j) { - const auto& cell_nodes = descriptor.cell_to_node_vector[j]; - - if constexpr (Dimension == 2) { - switch (descriptor.cell_type_vector[j]) { - case CellType::Triangle: { - cell_nb_faces[j] = 3; - // face 0 - Face f0({cell_nodes[1], cell_nodes[2]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); - - // face 1 - Face f1({cell_nodes[2], cell_nodes[0]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); - - // face 2 - Face f2({cell_nodes[0], cell_nodes[1]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); - break; - } - case CellType::Quadrangle: { - cell_nb_faces[j] = 4; - // face 0 - Face f0({cell_nodes[0], cell_nodes[1]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); - - // face 1 - Face f1({cell_nodes[1], cell_nodes[2]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); - - // face 2 - Face f2({cell_nodes[2], cell_nodes[3]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); - - // face 3 - Face f3({cell_nodes[3], cell_nodes[0]}, node_number_vector); - face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); - break; - } - default: { - std::ostringstream error_msg; - error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 2"; - throw UnexpectedError(error_msg.str()); - } - } - } else if constexpr (Dimension == 3) { - switch (descriptor.cell_type_vector[j]) { - case CellType::Tetrahedron: { - cell_nb_faces[j] = 4; - // face 0 - Face f0({cell_nodes[1], cell_nodes[2], cell_nodes[3]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); - - // face 1 - Face f1({cell_nodes[0], cell_nodes[3], cell_nodes[2]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); - - // face 2 - Face f2({cell_nodes[0], cell_nodes[1], cell_nodes[3]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); - - // face 3 - Face f3({cell_nodes[0], cell_nodes[2], cell_nodes[1]}, node_number_vector); - face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); - break; - } - case CellType::Hexahedron: { - // face 0 - Face f0({cell_nodes[3], cell_nodes[2], cell_nodes[1], cell_nodes[0]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); - - // face 1 - Face f1({cell_nodes[4], cell_nodes[5], cell_nodes[6], cell_nodes[7]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); - - // face 2 - Face f2({cell_nodes[0], cell_nodes[4], cell_nodes[7], cell_nodes[3]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); +// std::shared_ptr<IConnectivity> +// GmshReader::_buildConnectivity3D(const size_t nb_cells) +// { +// ConnectivityDescriptor descriptor; + +// descriptor.node_number_vector = m_mesh_data.__verticesNumbers; +// descriptor.cell_type_vector.resize(nb_cells); +// descriptor.cell_number_vector.resize(nb_cells); +// descriptor.cell_to_node_vector.resize(nb_cells); + +// const size_t nb_tetrahedra = m_mesh_data.__tetrahedra.size(); +// for (size_t j = 0; j < nb_tetrahedra; ++j) { +// descriptor.cell_to_node_vector[j].resize(4); +// for (int r = 0; r < 4; ++r) { +// descriptor.cell_to_node_vector[j][r] = m_mesh_data.__tetrahedra[j][r]; +// } +// descriptor.cell_type_vector[j] = CellType::Tetrahedron; +// descriptor.cell_number_vector[j] = m_mesh_data.__tetrahedra_number[j]; +// } +// const size_t nb_hexahedra = m_mesh_data.__hexahedra.size(); +// for (size_t j = 0; j < nb_hexahedra; ++j) { +// const size_t jh = nb_tetrahedra + j; +// descriptor.cell_to_node_vector[jh].resize(8); +// for (int r = 0; r < 8; ++r) { +// descriptor.cell_to_node_vector[jh][r] = m_mesh_data.__hexahedra[j][r]; +// } +// descriptor.cell_type_vector[jh] = CellType::Hexahedron; +// descriptor.cell_number_vector[jh] = m_mesh_data.__hexahedra_number[j]; +// } - // face 3 - Face f3({cell_nodes[1], cell_nodes[2], cell_nodes[6], cell_nodes[5]}, node_number_vector); - face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); +// std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; +// for (unsigned int r = 0; r < m_mesh_data.__tetrahedra_ref.size(); ++r) { +// const unsigned int elem_number = m_mesh_data.__tetrahedra_ref[r]; +// const unsigned int& ref = m_mesh_data.__tetrahedra_ref[r]; +// ref_cells_map[ref].push_back(elem_number); +// } - // face 4 - Face f4({cell_nodes[0], cell_nodes[1], cell_nodes[5], cell_nodes[4]}, node_number_vector); - face_cells_map[f4].emplace_back(std::make_tuple(j, 4, f4.reversed())); +// for (unsigned int j = 0; j < m_mesh_data.__hexahedra_ref.size(); ++j) { +// const size_t elem_number = nb_tetrahedra + j; +// const unsigned int& ref = m_mesh_data.__hexahedra_ref[j]; +// ref_cells_map[ref].push_back(elem_number); +// } - // face 5 - Face f5({cell_nodes[3], cell_nodes[7], cell_nodes[6], cell_nodes[2]}, node_number_vector); - face_cells_map[f5].emplace_back(std::make_tuple(j, 5, f5.reversed())); +// for (const auto& ref_cell_list : ref_cells_map) { +// Array<CellId> cell_list(ref_cell_list.second.size()); +// for (size_t j = 0; j < ref_cell_list.second.size(); ++j) { +// cell_list[j] = ref_cell_list.second[j]; +// } +// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_cell_list.first); +// descriptor.addRefItemList(RefCellList(physical_ref_id.refId(), cell_list)); +// } - cell_nb_faces[j] = 6; - break; - } - default: { - std::ostringstream error_msg; - error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 3"; - throw UnexpectedError(error_msg.str()); - } - } - } - } +// ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<3>(descriptor); + +// const auto& node_number_vector = descriptor.node_number_vector; + +// { +// using Face = ConnectivityFace<3>; +// const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { +// std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; +// for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { +// const auto& node_vector = descriptor.face_to_node_vector[l]; +// face_to_id_map[Face(node_vector, node_number_vector)] = l; +// } +// return face_to_id_map; +// }(); + +// std::unordered_map<int, FaceId> face_number_id_map = [&] { +// std::unordered_map<int, FaceId> face_number_id_map; +// for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { +// face_number_id_map[descriptor.face_number_vector[l]] = l; +// } +// Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); +// return face_number_id_map; +// }(); + +// std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; +// for (unsigned int f = 0; f < m_mesh_data.__triangles.size(); ++f) { +// const unsigned int face_id = [&] { +// auto i = face_to_id_map.find( +// Face({m_mesh_data.__triangles[f][0], m_mesh_data.__triangles[f][1], m_mesh_data.__triangles[f][2]}, +// node_number_vector)); +// if (i == face_to_id_map.end()) { +// throw NormalError("face not found"); +// } +// return i->second; +// }(); + +// const unsigned int& ref = m_mesh_data.__triangles_ref[f]; +// ref_faces_map[ref].push_back(face_id); + +// if (descriptor.face_number_vector[face_id] != m_mesh_data.__quadrangles_number[f]) { +// if (auto i_face = face_number_id_map.find(m_mesh_data.__quadrangles_number[f]); +// i_face != face_number_id_map.end()) { +// const int other_face_id = i_face->second; +// std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); + +// face_number_id_map.erase(descriptor.face_number_vector[face_id]); +// face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); + +// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; +// face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; +// } else { +// face_number_id_map.erase(descriptor.face_number_vector[face_id]); +// descriptor.face_number_vector[face_id] = m_mesh_data.__quadrangles_number[f]; +// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; +// } +// } +// } - { - descriptor.cell_to_face_vector.resize(descriptor.cell_to_node_vector.size()); - for (CellId j = 0; j < descriptor.cell_to_face_vector.size(); ++j) { - descriptor.cell_to_face_vector[j].resize(cell_nb_faces[j]); - } - FaceId l = 0; - for (const auto& face_cells_vector : face_cells_map) { - const auto& cells_vector = face_cells_vector.second; - for (unsigned short lj = 0; lj < cells_vector.size(); ++lj) { - const auto& [cell_number, cell_local_face, reversed] = cells_vector[lj]; - descriptor.cell_to_face_vector[cell_number][cell_local_face] = l; - } - ++l; - } - } +// for (unsigned int f = 0; f < m_mesh_data.__quadrangles.size(); ++f) { +// const unsigned int face_id = [&] { +// auto i = face_to_id_map.find(Face({m_mesh_data.__quadrangles[f][0], m_mesh_data.__quadrangles[f][1], +// m_mesh_data.__quadrangles[f][2], m_mesh_data.__quadrangles[f][3]}, +// node_number_vector)); +// if (i == face_to_id_map.end()) { +// throw NormalError("face not found"); +// } +// return i->second; +// }(); + +// const unsigned int& ref = m_mesh_data.__quadrangles_ref[f]; +// ref_faces_map[ref].push_back(face_id); + +// if (descriptor.face_number_vector[face_id] != m_mesh_data.__quadrangles_number[f]) { +// if (auto i_face = face_number_id_map.find(m_mesh_data.__quadrangles_number[f]); +// i_face != face_number_id_map.end()) { +// const int other_face_id = i_face->second; +// std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); + +// face_number_id_map.erase(descriptor.face_number_vector[face_id]); +// face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); + +// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; +// face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; +// } else { +// face_number_id_map.erase(descriptor.face_number_vector[face_id]); +// descriptor.face_number_vector[face_id] = m_mesh_data.__quadrangles_number[f]; +// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; +// } +// } +// } - { - descriptor.cell_face_is_reversed_vector.resize(descriptor.cell_to_node_vector.size()); - for (CellId j = 0; j < descriptor.cell_face_is_reversed_vector.size(); ++j) { - descriptor.cell_face_is_reversed_vector[j] = Array<bool>(cell_nb_faces[j]); - } - for (const auto& face_cells_vector : face_cells_map) { - const auto& cells_vector = face_cells_vector.second; - for (unsigned short lj = 0; lj < cells_vector.size(); ++lj) { - const auto& [cell_number, cell_local_face, reversed] = cells_vector[lj]; - descriptor.cell_face_is_reversed_vector[cell_number][cell_local_face] = reversed; - } - } - } +// for (const auto& ref_face_list : ref_faces_map) { +// Array<FaceId> face_list(ref_face_list.second.size()); +// for (size_t j = 0; j < ref_face_list.second.size(); ++j) { +// face_list[j] = ref_face_list.second[j]; +// } +// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_face_list.first); +// descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list}); +// } +// } - { - descriptor.face_to_node_vector.resize(face_cells_map.size()); - int l = 0; - for (const auto& face_info : face_cells_map) { - const Face& face = face_info.first; - descriptor.face_to_node_vector[l] = face.nodeIdList(); - ++l; - } - } +// ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<3>(descriptor); + +// { +// using Edge = ConnectivityFace<2>; +// const auto& node_number_vector = descriptor.node_number_vector; +// const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { +// std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; +// for (EdgeId l = 0; l < descriptor.edge_to_node_vector.size(); ++l) { +// const auto& node_vector = descriptor.edge_to_node_vector[l]; +// edge_to_id_map[Edge(node_vector, node_number_vector)] = l; +// } +// return edge_to_id_map; +// }(); + +// std::unordered_map<int, EdgeId> edge_number_id_map = [&] { +// std::unordered_map<int, EdgeId> edge_number_id_map; +// for (size_t l = 0; l < descriptor.edge_number_vector.size(); ++l) { +// edge_number_id_map[descriptor.edge_number_vector[l]] = l; +// } +// Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size()); +// return edge_number_id_map; +// }(); + +// std::map<unsigned int, std::vector<unsigned int>> ref_edges_map; +// for (unsigned int e = 0; e < m_mesh_data.__edges.size(); ++e) { +// const unsigned int edge_id = [&] { +// auto i = edge_to_id_map.find(Edge({m_mesh_data.__edges[e][0], m_mesh_data.__edges[e][1]}, +// node_number_vector)); if (i == edge_to_id_map.end()) { +// std::stringstream error_msg; +// error_msg << "edge " << m_mesh_data.__edges[e][0] << " not found"; +// throw NormalError(error_msg.str()); +// } +// return i->second; +// }(); +// const unsigned int& ref = m_mesh_data.__edges_ref[e]; +// ref_edges_map[ref].push_back(edge_id); + +// if (descriptor.edge_number_vector[edge_id] != m_mesh_data.__edges_number[e]) { +// if (auto i_edge = edge_number_id_map.find(m_mesh_data.__edges_number[e]); i_edge != edge_number_id_map.end()) +// { +// const int other_edge_id = i_edge->second; +// std::swap(descriptor.edge_number_vector[edge_id], descriptor.edge_number_vector[other_edge_id]); + +// edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); +// edge_number_id_map.erase(descriptor.edge_number_vector[other_edge_id]); + +// edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; +// edge_number_id_map[descriptor.edge_number_vector[other_edge_id]] = other_edge_id; +// } else { +// edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); +// descriptor.edge_number_vector[edge_id] = m_mesh_data.__edges_number[e]; +// edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; +// } +// } +// } - { - // Face numbers may change if numbers are provided in the file - descriptor.face_number_vector.resize(face_cells_map.size()); - for (size_t l = 0; l < face_cells_map.size(); ++l) { - descriptor.face_number_vector[l] = l; - } - } -} +// for (const auto& ref_edge_list : ref_edges_map) { +// Array<EdgeId> edge_list(ref_edge_list.second.size()); +// for (size_t j = 0; j < ref_edge_list.second.size(); ++j) { +// edge_list[j] = ref_edge_list.second[j]; +// } +// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_edge_list.first); +// descriptor.addRefItemList(RefEdgeList{physical_ref_id.refId(), edge_list}); +// } +// } -template <size_t Dimension> -void -GmshReader::__computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(ConnectivityDescriptor& descriptor) -{ - static_assert(Dimension == 3, "Invalid dimension to compute face-edge connectivities"); - using FaceEdgeInfo = std::tuple<FaceId, unsigned short, bool>; - using Edge = ConnectivityFace<2>; +// std::map<unsigned int, std::vector<unsigned int>> ref_points_map; +// for (unsigned int r = 0; r < m_mesh_data.__points.size(); ++r) { +// const unsigned int point_number = m_mesh_data.__points[r]; +// const unsigned int& ref = m_mesh_data.__points_ref[r]; +// ref_points_map[ref].push_back(point_number); +// } - const auto& node_number_vector = descriptor.node_number_vector; - Array<unsigned short> face_nb_edges(descriptor.face_to_node_vector.size()); - std::map<Edge, std::vector<FaceEdgeInfo>> edge_faces_map; - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - const auto& face_nodes = descriptor.face_to_node_vector[l]; - - face_nb_edges[l] = face_nodes.size(); - for (size_t r = 0; r < face_nodes.size() - 1; ++r) { - Edge e({face_nodes[r], face_nodes[r + 1]}, node_number_vector); - edge_faces_map[e].emplace_back(std::make_tuple(l, r, e.reversed())); - } - { - Edge e({face_nodes[face_nodes.size() - 1], face_nodes[0]}, node_number_vector); - edge_faces_map[e].emplace_back(std::make_tuple(l, face_nodes.size() - 1, e.reversed())); - } - } +// for (const auto& ref_point_list : ref_points_map) { +// Array<NodeId> point_list(ref_point_list.second.size()); +// for (size_t j = 0; j < ref_point_list.second.size(); ++j) { +// point_list[j] = ref_point_list.second[j]; +// } +// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_point_list.first); +// descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); +// } - std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_id_map; - { - descriptor.face_to_edge_vector.resize(descriptor.face_to_node_vector.size()); - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - descriptor.face_to_edge_vector[l].resize(face_nb_edges[l]); - } - EdgeId e = 0; - for (const auto& edge_faces_vector : edge_faces_map) { - const auto& faces_vector = edge_faces_vector.second; - for (unsigned short l = 0; l < faces_vector.size(); ++l) { - const auto& [face_number, face_local_edge, reversed] = faces_vector[l]; - descriptor.face_to_edge_vector[face_number][face_local_edge] = e; - } - edge_id_map[edge_faces_vector.first] = e; - ++e; - } - } +// descriptor.cell_owner_vector.resize(nb_cells); +// std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - { - descriptor.face_edge_is_reversed_vector.resize(descriptor.face_to_node_vector.size()); - for (FaceId j = 0; j < descriptor.face_edge_is_reversed_vector.size(); ++j) { - descriptor.face_edge_is_reversed_vector[j] = Array<bool>(face_nb_edges[j]); - } - for (const auto& edge_faces_vector : edge_faces_map) { - const auto& faces_vector = edge_faces_vector.second; - for (unsigned short lj = 0; lj < faces_vector.size(); ++lj) { - const auto& [face_number, face_local_edge, reversed] = faces_vector[lj]; - descriptor.face_edge_is_reversed_vector[face_number][face_local_edge] = reversed; - } - } - } +// descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); +// std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); - { - descriptor.edge_to_node_vector.resize(edge_faces_map.size()); - int e = 0; - for (const auto& edge_info : edge_faces_map) { - const Edge& edge = edge_info.first; - descriptor.edge_to_node_vector[e] = edge.nodeIdList(); - ++e; - } - } +// descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size()); +// std::fill(descriptor.edge_owner_vector.begin(), descriptor.edge_owner_vector.end(), parallel::rank()); - { - // Edge numbers may change if numbers are provided in the file - descriptor.edge_number_vector.resize(edge_faces_map.size()); - for (size_t e = 0; e < edge_faces_map.size(); ++e) { - descriptor.edge_number_vector[e] = e; - } - } +// descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); +// std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); - { - descriptor.cell_to_node_vector.reserve(descriptor.cell_to_node_vector.size()); - for (CellId j = 0; j < descriptor.cell_to_node_vector.size(); ++j) { - const auto& cell_nodes = descriptor.cell_to_node_vector[j]; - - switch (descriptor.cell_type_vector[j]) { - case CellType::Tetrahedron: { - constexpr int local_edge[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {2, 3}, {3, 1}}; - std::vector<unsigned int> cell_edge_vector; - cell_edge_vector.reserve(6); - for (int i_edge = 0; i_edge < 6; ++i_edge) { - const auto e = local_edge[i_edge]; - Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); - } - cell_edge_vector.push_back(i->second); - } - descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); - break; - } - case CellType::Hexahedron: { - constexpr int local_edge[12][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, - {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; - std::vector<unsigned int> cell_edge_vector; - cell_edge_vector.reserve(12); - for (int i_edge = 0; i_edge < 12; ++i_edge) { - const auto e = local_edge[i_edge]; - Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); - } - cell_edge_vector.push_back(i->second); - } - descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); - break; - } - default: { - std::stringstream error_msg; - error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 3"; - throw UnexpectedError(error_msg.str()); - } - } - } - } -} +// return Connectivity3D::build(descriptor); +// } void GmshReader::__proceedData() @@ -885,10 +957,10 @@ GmshReader::__proceedData() TinyVector<15, int> elementNumber = zero; std::vector<std::set<size_t>> elementReferences(15); - for (size_t i = 0; i < __elementType.size(); ++i) { - const int elementType = __elementType[i]; + for (size_t i = 0; i < m_mesh_data.__elementType.size(); ++i) { + const int elementType = m_mesh_data.__elementType[i]; elementNumber[elementType]++; - elementReferences[elementType].insert(__references[i]); + elementReferences[elementType].insert(m_mesh_data.__references[i]); } for (size_t i = 0; i < elementNumber.dimension(); ++i) { @@ -908,39 +980,39 @@ GmshReader::__proceedData() switch (i) { // Supported entities case 0: { // edges - __edges = Array<Edge>(elementNumber[i]); - __edges_ref.resize(elementNumber[i]); - __edges_number.resize(elementNumber[i]); + m_mesh_data.__edges = Array<GmshData::Edge>(elementNumber[i]); + m_mesh_data.__edges_ref.resize(elementNumber[i]); + m_mesh_data.__edges_number.resize(elementNumber[i]); break; } case 1: { // triangles - __triangles = Array<Triangle>(elementNumber[i]); - __triangles_ref.resize(elementNumber[i]); - __triangles_number.resize(elementNumber[i]); + m_mesh_data.__triangles = Array<GmshData::Triangle>(elementNumber[i]); + m_mesh_data.__triangles_ref.resize(elementNumber[i]); + m_mesh_data.__triangles_number.resize(elementNumber[i]); break; } case 2: { // quadrangles - __quadrangles = Array<Quadrangle>(elementNumber[i]); - __quadrangles_ref.resize(elementNumber[i]); - __quadrangles_number.resize(elementNumber[i]); + m_mesh_data.__quadrangles = Array<GmshData::Quadrangle>(elementNumber[i]); + m_mesh_data.__quadrangles_ref.resize(elementNumber[i]); + m_mesh_data.__quadrangles_number.resize(elementNumber[i]); break; } case 3: { // tetrahedra - __tetrahedra = Array<Tetrahedron>(elementNumber[i]); - __tetrahedra_ref.resize(elementNumber[i]); - __tetrahedra_number.resize(elementNumber[i]); + m_mesh_data.__tetrahedra = Array<GmshData::Tetrahedron>(elementNumber[i]); + m_mesh_data.__tetrahedra_ref.resize(elementNumber[i]); + m_mesh_data.__tetrahedra_number.resize(elementNumber[i]); break; } case 4: { // hexahedra - __hexahedra = Array<Hexahedron>(elementNumber[i]); - __hexahedra_ref.resize(elementNumber[i]); - __hexahedra_number.resize(elementNumber[i]); + m_mesh_data.__hexahedra = Array<GmshData::Hexahedron>(elementNumber[i]); + m_mesh_data.__hexahedra_ref.resize(elementNumber[i]); + m_mesh_data.__hexahedra_number.resize(elementNumber[i]); break; } case 14: { // point - __points = Array<Point>(elementNumber[i]); - __points_ref.resize(elementNumber[i]); - __points_number.resize(elementNumber[i]); + m_mesh_data.__points = Array<GmshData::Point>(elementNumber[i]); + m_mesh_data.__points_ref.resize(elementNumber[i]); + m_mesh_data.__points_number.resize(elementNumber[i]); break; } // Unsupported entities @@ -965,8 +1037,8 @@ GmshReader::__proceedData() std::cout << "- Building correspondance table\n"; int minNumber = std::numeric_limits<int>::max(); int maxNumber = std::numeric_limits<int>::min(); - for (size_t i = 0; i < __verticesNumbers.size(); ++i) { - const int& vertexNumber = __verticesNumbers[i]; + for (size_t i = 0; i < m_mesh_data.__verticesNumbers.size(); ++i) { + const int& vertexNumber = m_mesh_data.__verticesNumbers[i]; minNumber = std::min(minNumber, vertexNumber); maxNumber = std::max(maxNumber, vertexNumber); } @@ -976,112 +1048,112 @@ GmshReader::__proceedData() } // A value of -1 means that the vertex is unknown - __verticesCorrepondance.resize(maxNumber + 1, -1); + m_mesh_data.__verticesCorrepondance.resize(maxNumber + 1, -1); - for (size_t i = 0; i < __verticesNumbers.size(); ++i) { - __verticesCorrepondance[__verticesNumbers[i]] = i; + for (size_t i = 0; i < m_mesh_data.__verticesNumbers.size(); ++i) { + m_mesh_data.__verticesCorrepondance[m_mesh_data.__verticesNumbers[i]] = i; } // reset element number to count them while filling structures elementNumber = zero; // Element structures filling - for (size_t i = 0; i < __elementType.size(); ++i) { - std::vector<int>& elementVertices = __elementVertices[i]; - switch (__elementType[i]) { + for (size_t i = 0; i < m_mesh_data.__elementType.size(); ++i) { + std::vector<int>& elementVertices = m_mesh_data.__elementVertices[i]; + switch (m_mesh_data.__elementType[i]) { // Supported entities case 0: { // edge int& edgeNumber = elementNumber[0]; - const int a = __verticesCorrepondance[elementVertices[0]]; - const int b = __verticesCorrepondance[elementVertices[1]]; + const int a = m_mesh_data.__verticesCorrepondance[elementVertices[0]]; + const int b = m_mesh_data.__verticesCorrepondance[elementVertices[1]]; if ((a < 0) or (b < 0)) { throw NormalError("reading file '" + m_filename + "': error reading element " + std::to_string(i) + " [bad vertices definition]"); } - __edges[edgeNumber] = Edge(a, b); - __edges_ref[edgeNumber] = __references[i]; - __edges_number[edgeNumber] = __elementNumber[i]; + m_mesh_data.__edges[edgeNumber] = GmshData::Edge(a, b); + m_mesh_data.__edges_ref[edgeNumber] = m_mesh_data.__references[i]; + m_mesh_data.__edges_number[edgeNumber] = m_mesh_data.__elementNumber[i]; edgeNumber++; // one more edge break; } case 1: { // triangles int& triangleNumber = elementNumber[1]; - const int a = __verticesCorrepondance[elementVertices[0]]; - const int b = __verticesCorrepondance[elementVertices[1]]; - const int c = __verticesCorrepondance[elementVertices[2]]; + const int a = m_mesh_data.__verticesCorrepondance[elementVertices[0]]; + const int b = m_mesh_data.__verticesCorrepondance[elementVertices[1]]; + const int c = m_mesh_data.__verticesCorrepondance[elementVertices[2]]; if ((a < 0) or (b < 0) or (c < 0)) { throw NormalError("reading file '" + m_filename + "': error reading element " + std::to_string(i) + " [bad vertices definition]"); } - __triangles[triangleNumber] = Triangle(a, b, c); - __triangles_ref[triangleNumber] = __references[i]; - __triangles_number[triangleNumber] = __elementNumber[i]; + m_mesh_data.__triangles[triangleNumber] = GmshData::Triangle(a, b, c); + m_mesh_data.__triangles_ref[triangleNumber] = m_mesh_data.__references[i]; + m_mesh_data.__triangles_number[triangleNumber] = m_mesh_data.__elementNumber[i]; triangleNumber++; // one more triangle break; } case 2: { // quadrangle int& quadrilateralNumber = elementNumber[2]; - const int a = __verticesCorrepondance[elementVertices[0]]; - const int b = __verticesCorrepondance[elementVertices[1]]; - const int c = __verticesCorrepondance[elementVertices[2]]; - const int d = __verticesCorrepondance[elementVertices[3]]; + const int a = m_mesh_data.__verticesCorrepondance[elementVertices[0]]; + const int b = m_mesh_data.__verticesCorrepondance[elementVertices[1]]; + const int c = m_mesh_data.__verticesCorrepondance[elementVertices[2]]; + const int d = m_mesh_data.__verticesCorrepondance[elementVertices[3]]; if ((a < 0) or (b < 0) or (c < 0) or (d < 0)) { throw NormalError("reading file '" + m_filename + "': error reading element " + std::to_string(i) + " [bad vertices definition]"); } - __quadrangles[quadrilateralNumber] = Quadrangle(a, b, c, d); - __quadrangles_ref[quadrilateralNumber] = __references[i]; - __quadrangles_number[quadrilateralNumber] = __elementNumber[i]; + m_mesh_data.__quadrangles[quadrilateralNumber] = GmshData::Quadrangle(a, b, c, d); + m_mesh_data.__quadrangles_ref[quadrilateralNumber] = m_mesh_data.__references[i]; + m_mesh_data.__quadrangles_number[quadrilateralNumber] = m_mesh_data.__elementNumber[i]; quadrilateralNumber++; // one more quadrangle break; } case 3: { // tetrahedra int& tetrahedronNumber = elementNumber[3]; - const int a = __verticesCorrepondance[elementVertices[0]]; - const int b = __verticesCorrepondance[elementVertices[1]]; - const int c = __verticesCorrepondance[elementVertices[2]]; - const int d = __verticesCorrepondance[elementVertices[3]]; + const int a = m_mesh_data.__verticesCorrepondance[elementVertices[0]]; + const int b = m_mesh_data.__verticesCorrepondance[elementVertices[1]]; + const int c = m_mesh_data.__verticesCorrepondance[elementVertices[2]]; + const int d = m_mesh_data.__verticesCorrepondance[elementVertices[3]]; if ((a < 0) or (b < 0) or (c < 0) or (d < 0)) { throw NormalError("reading file '" + m_filename + "': error reading element " + std::to_string(i) + " [bad vertices definition]"); } - __tetrahedra[tetrahedronNumber] = Tetrahedron(a, b, c, d); - __tetrahedra_ref[tetrahedronNumber] = __references[i]; - __tetrahedra_number[tetrahedronNumber] = __elementNumber[i]; + m_mesh_data.__tetrahedra[tetrahedronNumber] = GmshData::Tetrahedron(a, b, c, d); + m_mesh_data.__tetrahedra_ref[tetrahedronNumber] = m_mesh_data.__references[i]; + m_mesh_data.__tetrahedra_number[tetrahedronNumber] = m_mesh_data.__elementNumber[i]; tetrahedronNumber++; // one more tetrahedron break; } case 4: { // hexaredron int& hexahedronNumber = elementNumber[4]; - const int a = __verticesCorrepondance[elementVertices[0]]; - const int b = __verticesCorrepondance[elementVertices[1]]; - const int c = __verticesCorrepondance[elementVertices[2]]; - const int d = __verticesCorrepondance[elementVertices[3]]; - const int e = __verticesCorrepondance[elementVertices[4]]; - const int f = __verticesCorrepondance[elementVertices[5]]; - const int g = __verticesCorrepondance[elementVertices[6]]; - const int h = __verticesCorrepondance[elementVertices[7]]; + const int a = m_mesh_data.__verticesCorrepondance[elementVertices[0]]; + const int b = m_mesh_data.__verticesCorrepondance[elementVertices[1]]; + const int c = m_mesh_data.__verticesCorrepondance[elementVertices[2]]; + const int d = m_mesh_data.__verticesCorrepondance[elementVertices[3]]; + const int e = m_mesh_data.__verticesCorrepondance[elementVertices[4]]; + const int f = m_mesh_data.__verticesCorrepondance[elementVertices[5]]; + const int g = m_mesh_data.__verticesCorrepondance[elementVertices[6]]; + const int h = m_mesh_data.__verticesCorrepondance[elementVertices[7]]; if ((a < 0) or (b < 0) or (c < 0) or (d < 0) or (e < 0) or (f < 0) or (g < 0) or (h < 0)) { throw NormalError("reading file '" + m_filename + "': error reading element " + std::to_string(i) + " [bad vertices definition]"); } - __hexahedra[hexahedronNumber] = Hexahedron(a, b, c, d, e, f, g, h); - __hexahedra_ref[hexahedronNumber] = __references[i]; - __hexahedra_number[hexahedronNumber] = __elementNumber[i]; + m_mesh_data.__hexahedra[hexahedronNumber] = GmshData::Hexahedron(a, b, c, d, e, f, g, h); + m_mesh_data.__hexahedra_ref[hexahedronNumber] = m_mesh_data.__references[i]; + m_mesh_data.__hexahedra_number[hexahedronNumber] = m_mesh_data.__elementNumber[i]; hexahedronNumber++; // one more hexahedron break; } // Unsupported entities case 14: { // point - int& point_number = elementNumber[14]; - const int a = __verticesCorrepondance[elementVertices[0]]; - __points[point_number] = a; - __points_ref[point_number] = __references[i]; - __points_number[point_number] = __elementNumber[i]; + int& point_number = elementNumber[14]; + const int a = m_mesh_data.__verticesCorrepondance[elementVertices[0]]; + m_mesh_data.__points[point_number] = a; + m_mesh_data.__points_ref[point_number] = m_mesh_data.__references[i]; + m_mesh_data.__points_number[point_number] = m_mesh_data.__elementNumber[i]; point_number++; break; } @@ -1128,463 +1200,57 @@ GmshReader::__proceedData() if ((dimension3_mask, elementNumber) > 0) { const size_t nb_cells = (dimension3_mask, elementNumber); - ConnectivityDescriptor descriptor; - - descriptor.node_number_vector = __verticesNumbers; - descriptor.cell_type_vector.resize(nb_cells); - descriptor.cell_number_vector.resize(nb_cells); - descriptor.cell_to_node_vector.resize(nb_cells); - - const size_t nb_tetrahedra = __tetrahedra.size(); - for (size_t j = 0; j < nb_tetrahedra; ++j) { - descriptor.cell_to_node_vector[j].resize(4); - for (int r = 0; r < 4; ++r) { - descriptor.cell_to_node_vector[j][r] = __tetrahedra[j][r]; - } - descriptor.cell_type_vector[j] = CellType::Tetrahedron; - descriptor.cell_number_vector[j] = __tetrahedra_number[j]; - } - const size_t nb_hexahedra = __hexahedra.size(); - for (size_t j = 0; j < nb_hexahedra; ++j) { - const size_t jh = nb_tetrahedra + j; - descriptor.cell_to_node_vector[jh].resize(8); - for (int r = 0; r < 8; ++r) { - descriptor.cell_to_node_vector[jh][r] = __hexahedra[j][r]; - } - descriptor.cell_type_vector[jh] = CellType::Hexahedron; - descriptor.cell_number_vector[jh] = __hexahedra_number[j]; - } - - std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; - for (unsigned int r = 0; r < __tetrahedra_ref.size(); ++r) { - const unsigned int elem_number = __tetrahedra_ref[r]; - const unsigned int& ref = __tetrahedra_ref[r]; - ref_cells_map[ref].push_back(elem_number); - } - - for (unsigned int j = 0; j < __hexahedra_ref.size(); ++j) { - const size_t elem_number = nb_tetrahedra + j; - const unsigned int& ref = __hexahedra_ref[j]; - ref_cells_map[ref].push_back(elem_number); - } - - for (const auto& ref_cell_list : ref_cells_map) { - Array<CellId> cell_list(ref_cell_list.second.size()); - for (size_t j = 0; j < ref_cell_list.second.size(); ++j) { - cell_list[j] = ref_cell_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_cell_list.first); - descriptor.addRefItemList(RefCellList(physical_ref_id.refId(), cell_list)); - } - - this->__computeCellFaceAndFaceNodeConnectivities<3>(descriptor); - - const auto& node_number_vector = descriptor.node_number_vector; - - { - using Face = ConnectivityFace<3>; - const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { - std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.face_to_node_vector[l]; - face_to_id_map[Face(node_vector, node_number_vector)] = l; - } - return face_to_id_map; - }(); - - std::unordered_map<int, FaceId> face_number_id_map = [&] { - std::unordered_map<int, FaceId> face_number_id_map; - for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { - face_number_id_map[descriptor.face_number_vector[l]] = l; - } - Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); - return face_number_id_map; - }(); + GmshConnectivityBuilder<3> connectivity_builder(m_mesh_data, nb_cells); - std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; - for (unsigned int f = 0; f < __triangles.size(); ++f) { - const unsigned int face_id = [&] { - auto i = - face_to_id_map.find(Face({__triangles[f][0], __triangles[f][1], __triangles[f][2]}, node_number_vector)); - if (i == face_to_id_map.end()) { - throw NormalError("face not found"); - } - return i->second; - }(); - - const unsigned int& ref = __triangles_ref[f]; - ref_faces_map[ref].push_back(face_id); - - if (descriptor.face_number_vector[face_id] != __quadrangles_number[f]) { - if (auto i_face = face_number_id_map.find(__quadrangles_number[f]); i_face != face_number_id_map.end()) { - const int other_face_id = i_face->second; - std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); - - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); - - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; - face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; - } else { - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - descriptor.face_number_vector[face_id] = __quadrangles_number[f]; - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; - } - } - } - - for (unsigned int f = 0; f < __quadrangles.size(); ++f) { - const unsigned int face_id = [&] { - auto i = face_to_id_map.find( - Face({__quadrangles[f][0], __quadrangles[f][1], __quadrangles[f][2], __quadrangles[f][3]}, - node_number_vector)); - if (i == face_to_id_map.end()) { - throw NormalError("face not found"); - } - return i->second; - }(); - - const unsigned int& ref = __quadrangles_ref[f]; - ref_faces_map[ref].push_back(face_id); - - if (descriptor.face_number_vector[face_id] != __quadrangles_number[f]) { - if (auto i_face = face_number_id_map.find(__quadrangles_number[f]); i_face != face_number_id_map.end()) { - const int other_face_id = i_face->second; - std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); - - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); - - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; - face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; - } else { - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - descriptor.face_number_vector[face_id] = __quadrangles_number[f]; - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; - } - } - } - - for (const auto& ref_face_list : ref_faces_map) { - Array<FaceId> face_list(ref_face_list.second.size()); - for (size_t j = 0; j < ref_face_list.second.size(); ++j) { - face_list[j] = ref_face_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_face_list.first); - descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list}); - } - } - this->__computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<3>(descriptor); - - { - using Edge = ConnectivityFace<2>; - const auto& node_number_vector = descriptor.node_number_vector; - const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { - std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; - for (EdgeId l = 0; l < descriptor.edge_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.edge_to_node_vector[l]; - edge_to_id_map[Edge(node_vector, node_number_vector)] = l; - } - return edge_to_id_map; - }(); - - std::unordered_map<int, EdgeId> edge_number_id_map = [&] { - std::unordered_map<int, EdgeId> edge_number_id_map; - for (size_t l = 0; l < descriptor.edge_number_vector.size(); ++l) { - edge_number_id_map[descriptor.edge_number_vector[l]] = l; - } - Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size()); - return edge_number_id_map; - }(); - - std::map<unsigned int, std::vector<unsigned int>> ref_edges_map; - for (unsigned int e = 0; e < __edges.size(); ++e) { - const unsigned int edge_id = [&] { - auto i = edge_to_id_map.find(Edge({__edges[e][0], __edges[e][1]}, node_number_vector)); - if (i == edge_to_id_map.end()) { - std::stringstream error_msg; - error_msg << "edge " << __edges[e][0] << " not found"; - throw NormalError(error_msg.str()); - } - return i->second; - }(); - const unsigned int& ref = __edges_ref[e]; - ref_edges_map[ref].push_back(edge_id); - - if (descriptor.edge_number_vector[edge_id] != __edges_number[e]) { - if (auto i_edge = edge_number_id_map.find(__edges_number[e]); i_edge != edge_number_id_map.end()) { - const int other_edge_id = i_edge->second; - std::swap(descriptor.edge_number_vector[edge_id], descriptor.edge_number_vector[other_edge_id]); - - edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); - edge_number_id_map.erase(descriptor.edge_number_vector[other_edge_id]); - - edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; - edge_number_id_map[descriptor.edge_number_vector[other_edge_id]] = other_edge_id; - } else { - edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); - descriptor.edge_number_vector[edge_id] = __edges_number[e]; - edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; - } - } - } - - for (const auto& ref_edge_list : ref_edges_map) { - Array<EdgeId> edge_list(ref_edge_list.second.size()); - for (size_t j = 0; j < ref_edge_list.second.size(); ++j) { - edge_list[j] = ref_edge_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_edge_list.first); - descriptor.addRefItemList(RefEdgeList{physical_ref_id.refId(), edge_list}); - } - } - - std::map<unsigned int, std::vector<unsigned int>> ref_points_map; - for (unsigned int r = 0; r < __points.size(); ++r) { - const unsigned int point_number = __points[r]; - const unsigned int& ref = __points_ref[r]; - ref_points_map[ref].push_back(point_number); - } - - for (const auto& ref_point_list : ref_points_map) { - Array<NodeId> point_list(ref_point_list.second.size()); - for (size_t j = 0; j < ref_point_list.second.size(); ++j) { - point_list[j] = ref_point_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_point_list.first); - descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); - } - - descriptor.cell_owner_vector.resize(nb_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - - descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); - std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); - - descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size()); - std::fill(descriptor.edge_owner_vector.begin(), descriptor.edge_owner_vector.end(), parallel::rank()); - - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); - - std::shared_ptr p_connectivity = Connectivity3D::build(descriptor); - Connectivity3D& connectivity = *p_connectivity; + std::shared_ptr p_connectivity = + std::dynamic_pointer_cast<const Connectivity3D>(connectivity_builder.connectivity()); + const Connectivity3D& connectivity = *p_connectivity; using MeshType = Mesh<Connectivity3D>; using Rd = TinyVector<3, double>; NodeValue<Rd> xr(connectivity); - for (NodeId i = 0; i < __vertices.size(); ++i) { - xr[i][0] = __vertices[i][0]; - xr[i][1] = __vertices[i][1]; - xr[i][2] = __vertices[i][2]; + for (NodeId i = 0; i < m_mesh_data.__vertices.size(); ++i) { + xr[i][0] = m_mesh_data.__vertices[i][0]; + xr[i][1] = m_mesh_data.__vertices[i][1]; + xr[i][2] = m_mesh_data.__vertices[i][2]; } m_mesh = std::make_shared<MeshType>(p_connectivity, xr); } else if ((dimension2_mask, elementNumber) > 0) { const size_t nb_cells = (dimension2_mask, elementNumber); - ConnectivityDescriptor descriptor; - - descriptor.node_number_vector = __verticesNumbers; - descriptor.cell_type_vector.resize(nb_cells); - descriptor.cell_number_vector.resize(nb_cells); - descriptor.cell_to_node_vector.resize(nb_cells); - - const size_t nb_triangles = __triangles.size(); - for (size_t j = 0; j < nb_triangles; ++j) { - descriptor.cell_to_node_vector[j].resize(3); - for (int r = 0; r < 3; ++r) { - descriptor.cell_to_node_vector[j][r] = __triangles[j][r]; - } - descriptor.cell_type_vector[j] = CellType::Triangle; - descriptor.cell_number_vector[j] = __triangles_number[j]; - } - - const size_t nb_quadrangles = __quadrangles.size(); - for (size_t j = 0; j < nb_quadrangles; ++j) { - const size_t jq = j + nb_triangles; - descriptor.cell_to_node_vector[jq].resize(4); - for (int r = 0; r < 4; ++r) { - descriptor.cell_to_node_vector[jq][r] = __quadrangles[j][r]; - } - descriptor.cell_type_vector[jq] = CellType::Quadrangle; - descriptor.cell_number_vector[jq] = __quadrangles_number[j]; - } - - std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; - for (unsigned int r = 0; r < __triangles_ref.size(); ++r) { - const unsigned int elem_number = __triangles_ref[r]; - const unsigned int& ref = __triangles_ref[r]; - ref_cells_map[ref].push_back(elem_number); - } - - for (unsigned int j = 0; j < __quadrangles_ref.size(); ++j) { - const size_t elem_number = nb_triangles + j; - const unsigned int& ref = __quadrangles_ref[j]; - ref_cells_map[ref].push_back(elem_number); - } - - for (const auto& ref_cell_list : ref_cells_map) { - Array<CellId> cell_list(ref_cell_list.second.size()); - for (size_t j = 0; j < ref_cell_list.second.size(); ++j) { - cell_list[j] = ref_cell_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_cell_list.first); - descriptor.addRefItemList(RefCellList(physical_ref_id.refId(), cell_list)); - } - - this->__computeCellFaceAndFaceNodeConnectivities<2>(descriptor); - - using Face = ConnectivityFace<2>; - const auto& node_number_vector = descriptor.node_number_vector; - const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { - std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.face_to_node_vector[l]; - face_to_id_map[Face(node_vector, node_number_vector)] = l; - } - return face_to_id_map; - }(); - - std::unordered_map<int, FaceId> face_number_id_map = [&] { - std::unordered_map<int, FaceId> face_number_id_map; - for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { - face_number_id_map[descriptor.face_number_vector[l]] = l; - } - Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); - return face_number_id_map; - }(); - - std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; - for (unsigned int e = 0; e < __edges.size(); ++e) { - const unsigned int edge_id = [&] { - auto i = face_to_id_map.find(Face({__edges[e][0], __edges[e][1]}, node_number_vector)); - if (i == face_to_id_map.end()) { - std::stringstream error_msg; - error_msg << "face " << __edges[e][0] << " not found"; - throw NormalError(error_msg.str()); - } - return i->second; - }(); - const unsigned int& ref = __edges_ref[e]; - ref_faces_map[ref].push_back(edge_id); - - if (descriptor.face_number_vector[edge_id] != __edges_number[e]) { - if (auto i_face = face_number_id_map.find(__edges_number[e]); i_face != face_number_id_map.end()) { - const int other_edge_id = i_face->second; - std::swap(descriptor.face_number_vector[edge_id], descriptor.face_number_vector[other_edge_id]); - - face_number_id_map.erase(descriptor.face_number_vector[edge_id]); - face_number_id_map.erase(descriptor.face_number_vector[other_edge_id]); - - face_number_id_map[descriptor.face_number_vector[edge_id]] = edge_id; - face_number_id_map[descriptor.face_number_vector[other_edge_id]] = other_edge_id; - } else { - face_number_id_map.erase(descriptor.face_number_vector[edge_id]); - descriptor.face_number_vector[edge_id] = __edges_number[e]; - face_number_id_map[descriptor.face_number_vector[edge_id]] = edge_id; - } - } - } - - for (const auto& ref_face_list : ref_faces_map) { - Array<FaceId> face_list(ref_face_list.second.size()); - for (size_t j = 0; j < ref_face_list.second.size(); ++j) { - face_list[j] = ref_face_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_face_list.first); - descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list}); - } - - std::map<unsigned int, std::vector<unsigned int>> ref_points_map; - for (unsigned int r = 0; r < __points.size(); ++r) { - const unsigned int point_number = __points[r]; - const unsigned int& ref = __points_ref[r]; - ref_points_map[ref].push_back(point_number); - } - - for (const auto& ref_point_list : ref_points_map) { - Array<NodeId> point_list(ref_point_list.second.size()); - for (size_t j = 0; j < ref_point_list.second.size(); ++j) { - point_list[j] = ref_point_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_point_list.first); - descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); - } - - descriptor.cell_owner_vector.resize(nb_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - - descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); - std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); + GmshConnectivityBuilder<2> connectivity_builder(m_mesh_data, nb_cells); - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); - - std::shared_ptr p_connectivity = Connectivity2D::build(descriptor); - Connectivity2D& connectivity = *p_connectivity; + std::shared_ptr p_connectivity = + std::dynamic_pointer_cast<const Connectivity2D>(connectivity_builder.connectivity()); + const Connectivity2D& connectivity = *p_connectivity; using MeshType = Mesh<Connectivity2D>; using Rd = TinyVector<2, double>; NodeValue<Rd> xr(connectivity); - for (NodeId i = 0; i < __vertices.size(); ++i) { - xr[i][0] = __vertices[i][0]; - xr[i][1] = __vertices[i][1]; + for (NodeId i = 0; i < m_mesh_data.__vertices.size(); ++i) { + xr[i][0] = m_mesh_data.__vertices[i][0]; + xr[i][1] = m_mesh_data.__vertices[i][1]; } m_mesh = std::make_shared<MeshType>(p_connectivity, xr); } else if ((dimension1_mask, elementNumber) > 0) { const size_t nb_cells = (dimension1_mask, elementNumber); - ConnectivityDescriptor descriptor; - - descriptor.node_number_vector = __verticesNumbers; - descriptor.cell_type_vector.resize(nb_cells); - descriptor.cell_number_vector.resize(nb_cells); - descriptor.cell_to_node_vector.resize(nb_cells); - - for (size_t j = 0; j < nb_cells; ++j) { - descriptor.cell_to_node_vector[j].resize(2); - for (int r = 0; r < 2; ++r) { - descriptor.cell_to_node_vector[j][r] = __edges[j][r]; - } - descriptor.cell_type_vector[j] = CellType::Line; - descriptor.cell_number_vector[j] = __edges_number[j]; - } - - std::map<unsigned int, std::vector<unsigned int>> ref_points_map; - for (unsigned int r = 0; r < __points.size(); ++r) { - const unsigned int point_number = __points[r]; - const unsigned int& ref = __points_ref[r]; - ref_points_map[ref].push_back(point_number); - } - - for (const auto& ref_point_list : ref_points_map) { - Array<NodeId> point_list(ref_point_list.second.size()); - for (size_t j = 0; j < ref_point_list.second.size(); ++j) { - point_list[j] = ref_point_list.second[j]; - } - const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_point_list.first); - descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); - } - - descriptor.cell_owner_vector.resize(nb_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + GmshConnectivityBuilder<1> connectivity_builder(m_mesh_data, nb_cells); - std::shared_ptr p_connectivity = Connectivity1D::build(descriptor); - Connectivity1D& connectivity = *p_connectivity; + std::shared_ptr p_connectivity = + std::dynamic_pointer_cast<const Connectivity1D>(connectivity_builder.connectivity()); + const Connectivity1D& connectivity = *p_connectivity; using MeshType = Mesh<Connectivity1D>; using Rd = TinyVector<1, double>; NodeValue<Rd> xr(connectivity); - for (NodeId i = 0; i < __vertices.size(); ++i) { - xr[i][0] = __vertices[i][0]; + for (NodeId i = 0; i < m_mesh_data.__vertices.size(); ++i) { + xr[i][0] = m_mesh_data.__vertices[i][0]; } m_mesh = std::make_shared<MeshType>(p_connectivity, xr); diff --git a/src/mesh/GmshReader.hpp b/src/mesh/GmshReader.hpp index 2b95822863c4ce87395ffc3173ca5934287fd40e..ae18d30ca3acd989f7a48d610afb458de8c4342d 100644 --- a/src/mesh/GmshReader.hpp +++ b/src/mesh/GmshReader.hpp @@ -2,21 +2,19 @@ #define GMSH_READER_HPP #include <algebra/TinyVector.hpp> - -#include <utils/Array.hpp> - -#include <mesh/Mesh.hpp> +#include <mesh/IMesh.hpp> +#include <mesh/MeshBuilderBase.hpp> #include <mesh/RefId.hpp> +#include <utils/Array.hpp> #include <array> #include <fstream> #include <map> +#include <memory> #include <string> #include <vector> -class ConnectivityDescriptor; - -class GmshReader +class GmshReader : public MeshBuilderBase { public: using R3 = TinyVector<3, double>; @@ -71,73 +69,80 @@ class GmshReader ~PhysicalRefId() = default; }; + struct GmshData + { + /** + * Gmsh format provides a numbered, none ordrered and none dense + * vertices list, this stores the number of read vertices. + */ + std::vector<int> __verticesNumbers; + + Array<R3> __vertices; + + using Point = unsigned int; + Array<Point> __points; + std::vector<int> __points_ref; + std::vector<int> __points_number; + + using Edge = TinyVector<2, unsigned int>; + Array<Edge> __edges; + std::vector<int> __edges_ref; + std::vector<int> __edges_number; + + using Triangle = TinyVector<3, unsigned int>; + Array<Triangle> __triangles; + std::vector<int> __triangles_ref; + std::vector<int> __triangles_number; + + using Quadrangle = TinyVector<4, unsigned int>; + Array<Quadrangle> __quadrangles; + std::vector<int> __quadrangles_ref; + std::vector<int> __quadrangles_number; + + using Tetrahedron = TinyVector<4, unsigned int>; + Array<Tetrahedron> __tetrahedra; + std::vector<int> __tetrahedra_ref; + std::vector<int> __tetrahedra_number; + + using Hexahedron = TinyVector<8, unsigned int>; + Array<Hexahedron> __hexahedra; + std::vector<int> __hexahedra_ref; + std::vector<int> __hexahedra_number; + + /** + * Gmsh format provides a numbered, none ordrered and none dense + * vertices list, this provides vertices renumbering correspondence + */ + std::vector<int> __verticesCorrepondance; + + /** + * elements types + */ + std::vector<int> __elementNumber; + + /** + * elements types + */ + std::vector<short> __elementType; + + /** + * References + */ + std::vector<int> __references; + + /** + * References + */ + std::vector<std::vector<int> > __elementVertices; + + std::map<unsigned int, PhysicalRefId> m_physical_ref_map; + }; + private: std::ifstream m_fin; const std::string m_filename; - /** - * Gmsh format provides a numbered, none ordrered and none dense - * vertices list, this stores the number of read vertices. - */ - std::vector<int> __verticesNumbers; - - Array<R3> __vertices; - - using Point = unsigned int; - Array<Point> __points; - std::vector<int> __points_ref; - std::vector<int> __points_number; - - using Edge = TinyVector<2, unsigned int>; - Array<Edge> __edges; - std::vector<int> __edges_ref; - std::vector<int> __edges_number; - - using Triangle = TinyVector<3, unsigned int>; - Array<Triangle> __triangles; - std::vector<int> __triangles_ref; - std::vector<int> __triangles_number; - - using Quadrangle = TinyVector<4, unsigned int>; - Array<Quadrangle> __quadrangles; - std::vector<int> __quadrangles_ref; - std::vector<int> __quadrangles_number; - - using Tetrahedron = TinyVector<4, unsigned int>; - Array<Tetrahedron> __tetrahedra; - std::vector<int> __tetrahedra_ref; - std::vector<int> __tetrahedra_number; - - using Hexahedron = TinyVector<8, unsigned int>; - Array<Hexahedron> __hexahedra; - std::vector<int> __hexahedra_ref; - std::vector<int> __hexahedra_number; - - /** - * Gmsh format provides a numbered, none ordrered and none dense - * vertices list, this provides vertices renumbering correspondance - */ - std::vector<int> __verticesCorrepondance; - - /** - * elements types - */ - std::vector<int> __elementNumber; - - /** - * elements types - */ - std::vector<short> __elementType; - - /** - * References - */ - std::vector<int> __references; - - /** - * References - */ - std::vector<std::vector<int> > __elementVertices; + GmshData m_mesh_data; /** * Stores the number of nodes associated to each primitive @@ -157,11 +162,6 @@ class GmshReader */ std::map<int, std::string> __primitivesNames; - bool __binary; /**< true if binary format */ - bool __convertEndian; /**< true if needs to adapt endianess */ - - std::map<unsigned int, PhysicalRefId> m_physical_ref_map; - int _getInteger() { @@ -263,24 +263,7 @@ class GmshReader */ void __readPhysicalNames2_2(); - template <size_t Dimension> - void __computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& descriptor); - - template <size_t Dimension> - void __computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(ConnectivityDescriptor& descriptor); - - template <int Dimension> - void _dispatch(); - - std::shared_ptr<IMesh> m_mesh; - public: - std::shared_ptr<IMesh> - mesh() const - { - return m_mesh; - } - GmshReader(const std::string& filename); ~GmshReader() = default; }; diff --git a/src/mesh/IMesh.cpp b/src/mesh/IMesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb2accc141ed09c778237587373494797fee726d --- /dev/null +++ b/src/mesh/IMesh.cpp @@ -0,0 +1,8 @@ +#include <mesh/IMesh.hpp> + +#include <mesh/MeshDataManager.hpp> + +IMesh::~IMesh() +{ + MeshDataManager::instance().deleteMeshData(*this); +} diff --git a/src/mesh/IMesh.hpp b/src/mesh/IMesh.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cb524849aaf0a7f994d8fb34fe2e97508c5e4f8a --- /dev/null +++ b/src/mesh/IMesh.hpp @@ -0,0 +1,18 @@ +#ifndef I_MESH_HPP +#define I_MESH_HPP + +#include <cstddef> + +class IMesh +{ + public: + virtual size_t dimension() const = 0; + + IMesh(const IMesh&) = delete; + IMesh(IMesh&&) = delete; + + IMesh() = default; + virtual ~IMesh(); +}; + +#endif // I_MESH_HPP diff --git a/src/mesh/IMeshData.hpp b/src/mesh/IMeshData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8cad9586d201de6b383bbbfaf94f09e5797078e5 --- /dev/null +++ b/src/mesh/IMeshData.hpp @@ -0,0 +1,10 @@ +#ifndef I_MESH_DATA_HPP +#define I_MESH_DATA_HPP + +class IMeshData +{ + public: + virtual ~IMeshData() = default; +}; + +#endif // I_MESH_DATA_HPP diff --git a/src/mesh/ItemId.hpp b/src/mesh/ItemId.hpp index c52958f8bd8d48537c8a99666169d0fd1968c003..e62fe7bae6b75f37285257d4211e7ad70d8b6a26 100644 --- a/src/mesh/ItemId.hpp +++ b/src/mesh/ItemId.hpp @@ -25,9 +25,7 @@ class ItemIdT constexpr ItemIdT operator++(int) { - ItemIdT item_id(m_id); - ++m_id; - return std::move(item_id); + return ItemIdT{m_id++}; } PUGS_INLINE diff --git a/src/mesh/ItemValue.hpp b/src/mesh/ItemValue.hpp index eb9f23113c3d2dc6694a06fd1af080eaf4705a49..a9049a394d225f68086a8c4038d8159928405612 100644 --- a/src/mesh/ItemValue.hpp +++ b/src/mesh/ItemValue.hpp @@ -40,7 +40,7 @@ class ItemValue friend PUGS_INLINE ItemValue<std::remove_const_t<DataType>, item_type, ConnectivityPtr> copy(const ItemValue<DataType, item_type, ConnectivityPtr>& source) { - ItemValue<std::remove_const_t<DataType>, item_type, ConnectivityPtr> image(source); + ItemValue<std::remove_const_t<DataType>, item_type, ConnectivityPtr> image(*source.connectivity_ptr()); image.m_values = copy(source.m_values); return image; diff --git a/src/mesh/ItemValueUtils.hpp b/src/mesh/ItemValueUtils.hpp index ca0c38ecdbb4ec48271be555241fbd45f02c66e4..a1039fdbdc8933c27d6ce19ec978894b329520c1 100644 --- a/src/mesh/ItemValueUtils.hpp +++ b/src/mesh/ItemValueUtils.hpp @@ -10,46 +10,22 @@ #include <iostream> -template <typename DataType, ItemType item_type> +template <typename DataType, ItemType item_type, typename ConnectivityPtr> std::remove_const_t<DataType> -min(const ItemValue<DataType, item_type>& item_value) +min(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) { - using ItemValueType = ItemValue<DataType, item_type>; - using data_type = std::remove_const_t<typename ItemValueType::data_type>; - using index_type = typename ItemValueType::index_type; - - const auto& is_owned = [&](const IConnectivity& connectivity) { - Assert((connectivity.dimension() > 0) and (connectivity.dimension() <= 3), "unexpected connectivity dimension"); - - switch (connectivity.dimension()) { - case 1: { - const auto& connectivity_1d = static_cast<const Connectivity1D&>(connectivity); - return connectivity_1d.isOwned<item_type>(); - break; - } - case 2: { - const auto& connectivity_2d = static_cast<const Connectivity2D&>(connectivity); - return connectivity_2d.isOwned<item_type>(); - break; - } - case 3: { - const auto& connectivity_3d = static_cast<const Connectivity3D&>(connectivity); - return connectivity_3d.isOwned<item_type>(); - break; - } - default: { - throw UnexpectedError("unexpected dimension"); - } - } - }(*item_value.connectivity_ptr()); + using ItemValueType = ItemValue<DataType, item_type, ConnectivityPtr>; + using ItemIsOwnedType = ItemValue<const bool, item_type>; + using data_type = std::remove_const_t<typename ItemValueType::data_type>; + using index_type = typename ItemValueType::index_type; - using IsOwnedType = std::remove_reference_t<decltype(is_owned)>; + static_assert(not std::is_same_v<data_type, bool>, "min cannot be called on boolean arrays"); class ItemValueMin { private: const ItemValueType& m_item_value; - const IsOwnedType& m_is_owned; + const ItemIsOwnedType m_is_owned; public: PUGS_INLINE @@ -86,8 +62,32 @@ min(const ItemValue<DataType, item_type>& item_value) } PUGS_INLINE - ItemValueMin(const ItemValueType& item_value, const IsOwnedType& is_owned) - : m_item_value(item_value), m_is_owned(is_owned) + ItemValueMin(const ItemValueType& item_value) + : m_item_value(item_value), m_is_owned([&](const IConnectivity& connectivity) { + Assert((connectivity.dimension() > 0) and (connectivity.dimension() <= 3), + "unexpected connectivity dimension"); + + switch (connectivity.dimension()) { + case 1: { + const auto& connectivity_1d = static_cast<const Connectivity1D&>(connectivity); + return connectivity_1d.isOwned<item_type>(); + break; + } + case 2: { + const auto& connectivity_2d = static_cast<const Connectivity2D&>(connectivity); + return connectivity_2d.isOwned<item_type>(); + break; + } + case 3: { + const auto& connectivity_3d = static_cast<const Connectivity3D&>(connectivity); + return connectivity_3d.isOwned<item_type>(); + break; + } + default: { + throw UnexpectedError("unexpected dimension"); + } + } + }(*item_value.connectivity_ptr())) { ; } @@ -96,50 +96,25 @@ min(const ItemValue<DataType, item_type>& item_value) ~ItemValueMin() = default; }; - const DataType local_min = ItemValueMin{item_value, is_owned}; + const DataType local_min = ItemValueMin{item_value}; return parallel::allReduceMin(local_min); } -template <typename DataType, ItemType item_type> +template <typename DataType, ItemType item_type, typename ConnectivityPtr> std::remove_const_t<DataType> -max(const ItemValue<DataType, item_type>& item_value) +max(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) { - using ItemValueType = ItemValue<DataType, item_type>; - using data_type = std::remove_const_t<typename ItemValueType::data_type>; - using index_type = typename ItemValueType::index_type; - - const auto& is_owned = [&](const IConnectivity& connectivity) { - Assert((connectivity.dimension() > 0) and (connectivity.dimension() <= 3), "unexpected connectivity dimension"); - - switch (connectivity.dimension()) { - case 1: { - const auto& connectivity_1d = static_cast<const Connectivity1D&>(connectivity); - return connectivity_1d.isOwned<item_type>(); - break; - } - case 2: { - const auto& connectivity_2d = static_cast<const Connectivity2D&>(connectivity); - return connectivity_2d.isOwned<item_type>(); - break; - } - case 3: { - const auto& connectivity_3d = static_cast<const Connectivity3D&>(connectivity); - return connectivity_3d.isOwned<item_type>(); - break; - } - default: { - throw UnexpectedError("unexpected dimension"); - } - } - }(*item_value.connectivity_ptr()); - - using IsOwnedType = std::remove_reference_t<decltype(is_owned)>; + using ItemValueType = ItemValue<DataType, item_type, ConnectivityPtr>; + using ItemIsOwnedType = ItemValue<const bool, item_type>; + using data_type = std::remove_const_t<typename ItemValueType::data_type>; + using index_type = typename ItemValueType::index_type; + static_assert(not std::is_same_v<data_type, bool>, "min cannot be called on boolean arrays"); class ItemValueMax { private: const ItemValueType& m_item_value; - const IsOwnedType& m_is_owned; + const ItemIsOwnedType m_is_owned; public: PUGS_INLINE @@ -176,8 +151,32 @@ max(const ItemValue<DataType, item_type>& item_value) } PUGS_INLINE - ItemValueMax(const ItemValueType& item_value, const IsOwnedType& is_owned) - : m_item_value(item_value), m_is_owned(is_owned) + ItemValueMax(const ItemValueType& item_value) + : m_item_value(item_value), m_is_owned([&](const IConnectivity& connectivity) { + Assert((connectivity.dimension() > 0) and (connectivity.dimension() <= 3), + "unexpected connectivity dimension"); + + switch (connectivity.dimension()) { + case 1: { + const auto& connectivity_1d = static_cast<const Connectivity1D&>(connectivity); + return connectivity_1d.isOwned<item_type>(); + break; + } + case 2: { + const auto& connectivity_2d = static_cast<const Connectivity2D&>(connectivity); + return connectivity_2d.isOwned<item_type>(); + break; + } + case 3: { + const auto& connectivity_3d = static_cast<const Connectivity3D&>(connectivity); + return connectivity_3d.isOwned<item_type>(); + break; + } + default: { + throw UnexpectedError("unexpected dimension"); + } + } + }(*item_value.connectivity_ptr())) { ; } @@ -194,42 +193,18 @@ template <typename DataType, ItemType item_type> std::remove_const_t<DataType> sum(const ItemValue<DataType, item_type>& item_value) { - using ItemValueType = ItemValue<DataType, item_type>; - using data_type = std::remove_const_t<typename ItemValueType::data_type>; - using index_type = typename ItemValueType::index_type; - - const auto& is_owned = [&](const IConnectivity& connectivity) { - Assert((connectivity.dimension() > 0) and (connectivity.dimension() <= 3), "unexpected connectivity dimension"); - - switch (connectivity.dimension()) { - case 1: { - const auto& connectivity_1d = static_cast<const Connectivity1D&>(connectivity); - return connectivity_1d.isOwned<item_type>(); - break; - } - case 2: { - const auto& connectivity_2d = static_cast<const Connectivity2D&>(connectivity); - return connectivity_2d.isOwned<item_type>(); - break; - } - case 3: { - const auto& connectivity_3d = static_cast<const Connectivity3D&>(connectivity); - return connectivity_3d.isOwned<item_type>(); - break; - } - default: { - throw UnexpectedError("unexpected dimension"); - } - } - }(*item_value.connectivity_ptr()); + using ItemValueType = ItemValue<DataType, item_type>; + using ItemIsOwnedType = ItemValue<const bool, item_type>; + using data_type = std::remove_const_t<typename ItemValueType::data_type>; + using index_type = typename ItemValueType::index_type; - using IsOwnedType = std::remove_reference_t<decltype(is_owned)>; + static_assert(not std::is_same_v<data_type, bool>, "sum cannot be called on boolean arrays"); class ItemValueSum { private: const ItemValueType& m_item_value; - const IsOwnedType& m_is_owned; + const ItemIsOwnedType m_is_owned; public: PUGS_INLINE @@ -268,8 +243,32 @@ sum(const ItemValue<DataType, item_type>& item_value) } PUGS_INLINE - ItemValueSum(const ItemValueType& item_value, const IsOwnedType& is_owned) - : m_item_value(item_value), m_is_owned(is_owned) + ItemValueSum(const ItemValueType& item_value) + : m_item_value(item_value), m_is_owned([&](const IConnectivity& connectivity) { + Assert((connectivity.dimension() > 0) and (connectivity.dimension() <= 3), + "unexpected connectivity dimension"); + + switch (connectivity.dimension()) { + case 1: { + const auto& connectivity_1d = static_cast<const Connectivity1D&>(connectivity); + return connectivity_1d.isOwned<item_type>(); + break; + } + case 2: { + const auto& connectivity_2d = static_cast<const Connectivity2D&>(connectivity); + return connectivity_2d.isOwned<item_type>(); + break; + } + case 3: { + const auto& connectivity_3d = static_cast<const Connectivity3D&>(connectivity); + return connectivity_3d.isOwned<item_type>(); + break; + } + default: { + throw UnexpectedError("unexpected dimension"); + } + } + }(*item_value.connectivity_ptr())) { ; } @@ -278,7 +277,7 @@ sum(const ItemValue<DataType, item_type>& item_value) ~ItemValueSum() = default; }; - const DataType local_sum = ItemValueSum{item_value, is_owned}; + const DataType local_sum = ItemValueSum{item_value}; return parallel::allReduceSum(local_sum); } diff --git a/src/mesh/LogicalConnectivityBuilder.cpp b/src/mesh/LogicalConnectivityBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfeddbeca5471469ce5dee98382464a7cedc9746 --- /dev/null +++ b/src/mesh/LogicalConnectivityBuilder.cpp @@ -0,0 +1,643 @@ +#include <mesh/LogicalConnectivityBuilder.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityDescriptor.hpp> +#include <mesh/RefId.hpp> +#include <utils/Array.hpp> +#include <utils/Messenger.hpp> + +#include <unordered_map> + +template <size_t Dimension> +inline void +LogicalConnectivityBuilder::_buildBoundaryNodeList(const TinyVector<Dimension, uint64_t>&, ConnectivityDescriptor&) +{ + static_assert(Dimension <= 3, "unexpected dimension"); +} + +template <> +inline void +LogicalConnectivityBuilder::_buildBoundaryNodeList( + const TinyVector<1, uint64_t>& cell_size, // clazy:exclude=function-args-by-value + ConnectivityDescriptor& descriptor) +{ + { // xmin + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = 0; + descriptor.addRefItemList(RefNodeList{RefId{0, "XMIN"}, boundary_nodes}); + } + + { // xmax + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = cell_size[0]; + descriptor.addRefItemList(RefNodeList{RefId{1, "XMAX"}, boundary_nodes}); + } +} + +template <> +void +LogicalConnectivityBuilder::_buildBoundaryNodeList( + const TinyVector<2, uint64_t>& cell_size, // clazy:exclude=function-args-by-value + ConnectivityDescriptor& descriptor) +{ + const TinyVector<2, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1}; + + const auto node_number = [&](const TinyVector<2, uint64_t> node_logic_id) { + return node_logic_id[0] * node_size[1] + node_logic_id[1]; + }; + + { // xminymin + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({0, 0}); + descriptor.addRefItemList(RefNodeList{RefId{10, "XMINYMIN"}, boundary_nodes}); + } + + { // xmaxymin + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({cell_size[0], 0}); + descriptor.addRefItemList(RefNodeList{RefId{11, "XMAXYMIN"}, boundary_nodes}); + } + + { // xmaxymax + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({cell_size[0], cell_size[1]}); + descriptor.addRefItemList(RefNodeList{RefId{12, "XMAXYMAX"}, boundary_nodes}); + } + + { // xminymax + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({0, cell_size[1]}); + descriptor.addRefItemList(RefNodeList{RefId{13, "XMINYMAX"}, boundary_nodes}); + } +} + +template <> +void +LogicalConnectivityBuilder::_buildBoundaryNodeList(const TinyVector<3, uint64_t>& cell_size, + ConnectivityDescriptor& descriptor) +{ + const TinyVector<3, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1, cell_size[2] + 1}; + + const auto node_number = [&](const TinyVector<3, uint64_t>& node_logic_id) { + return (node_logic_id[0] * node_size[1] + node_logic_id[1]) * node_size[2] + node_logic_id[2]; + }; + + { // xminyminzmin + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({0, 0, 0}); + descriptor.addRefItemList(RefNodeList{RefId{10, "XMINYMINZMIN"}, boundary_nodes}); + } + + { // xmaxyminzmin + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({cell_size[0], 0, 0}); + descriptor.addRefItemList(RefNodeList{RefId{11, "XMAXYMINZMIN"}, boundary_nodes}); + } + + { // xmaxymaxzmin + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({cell_size[0], cell_size[1], 0}); + descriptor.addRefItemList(RefNodeList{RefId{12, "XMAXYMAXZMIN"}, boundary_nodes}); + } + + { // xminymaxzmin + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({0, cell_size[1], 0}); + descriptor.addRefItemList(RefNodeList{RefId{13, "XMINYMAXZMIN"}, boundary_nodes}); + } + + { // xminyminzmax + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({0, 0, cell_size[2]}); + descriptor.addRefItemList(RefNodeList{RefId{14, "XMINYMINZMAX"}, boundary_nodes}); + } + + { // xmaxyminzmax + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({cell_size[0], 0, cell_size[2]}); + descriptor.addRefItemList(RefNodeList{RefId{15, "XMAXYMINZMAX"}, boundary_nodes}); + } + + { // xmaxymaxzmax + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({cell_size[0], cell_size[1], cell_size[2]}); + descriptor.addRefItemList(RefNodeList{RefId{16, "XMAXYMAXZMAX"}, boundary_nodes}); + } + + { // xminymaxzmax + Array<NodeId> boundary_nodes(1); + boundary_nodes[0] = node_number({0, cell_size[1], cell_size[2]}); + descriptor.addRefItemList(RefNodeList{RefId{17, "XMINYMAXZMAX"}, boundary_nodes}); + } +} + +template <size_t Dimension> +void +LogicalConnectivityBuilder::_buildBoundaryEdgeList(const TinyVector<Dimension, uint64_t>&, ConnectivityDescriptor&) +{ + static_assert(Dimension == 3, "unexpected dimension"); +} + +template <> +void +LogicalConnectivityBuilder::_buildBoundaryEdgeList(const TinyVector<3, uint64_t>& cell_size, + ConnectivityDescriptor& descriptor) +{ + using Edge = ConnectivityFace<2>; + const auto& node_number_vector = descriptor.node_number_vector; + const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { + std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; + for (EdgeId l = 0; l < descriptor.edge_to_node_vector.size(); ++l) { + const auto& node_vector = descriptor.edge_to_node_vector[l]; + edge_to_id_map[Edge(node_vector, node_number_vector)] = l; + } + return edge_to_id_map; + }(); + + std::unordered_map<int, EdgeId> edge_number_id_map = [&] { + std::unordered_map<int, EdgeId> edge_number_id_map; + for (size_t l = 0; l < descriptor.edge_number_vector.size(); ++l) { + edge_number_id_map[descriptor.edge_number_vector[l]] = l; + } + Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size()); + return edge_number_id_map; + }(); + + const TinyVector<3, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1, cell_size[2] + 1}; + const auto node_number = [&](const TinyVector<3, uint64_t>& node_logic_id) { + return (node_logic_id[0] * node_size[1] + node_logic_id[1]) * node_size[2] + node_logic_id[2]; + }; + + { // Ridge edges in direction of Z axis + const auto add_ref_item_list_along_z = [&](const size_t i, const size_t j, const unsigned ref_id, + const std::string& ref_name) { + Array<EdgeId> boundary_edges(cell_size[2]); + size_t l = 0; + for (size_t k = 0; k < cell_size[2]; ++k) { + const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i, j, k + 1}); + + auto i_edge = edge_to_id_map.find(Edge{{node_0_id, node_1_id}, descriptor.node_number_vector}); + Assert(i_edge != edge_to_id_map.end()); + + boundary_edges[l++] = i_edge->second; + } + Assert(l == cell_size[2]); + descriptor.addRefItemList(RefEdgeList{RefId{ref_id, ref_name}, boundary_edges}); + }; + + add_ref_item_list_along_z(0, 0, 20, "XMINYMIN"); + add_ref_item_list_along_z(0, cell_size[1], 21, "XMINYMAX"); + add_ref_item_list_along_z(cell_size[0], cell_size[1], 22, "XMAXYMAX"); + add_ref_item_list_along_z(cell_size[0], 0, 23, "XMAXYMIN"); + } + + { // Ridge edges in direction of Y axis + const auto add_ref_item_list_along_y = [&](const size_t i, const size_t k, const unsigned ref_id, + const std::string& ref_name) { + Array<EdgeId> boundary_edges(cell_size[1]); + size_t l = 0; + for (size_t j = 0; j < cell_size[1]; ++j) { + const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k}); + + auto i_edge = edge_to_id_map.find(Edge{{node_0_id, node_1_id}, descriptor.node_number_vector}); + Assert(i_edge != edge_to_id_map.end()); + + boundary_edges[l++] = i_edge->second; + } + Assert(l == cell_size[1]); + descriptor.addRefItemList(RefEdgeList{RefId{ref_id, ref_name}, boundary_edges}); + }; + + add_ref_item_list_along_y(0, 0, 24, "XMINZMIN"); + add_ref_item_list_along_y(0, cell_size[2], 25, "XMINZMAX"); + add_ref_item_list_along_y(cell_size[0], cell_size[2], 26, "XMAXZMAX"); + add_ref_item_list_along_y(cell_size[0], 0, 27, "XMAXZMIN"); + } + + { // Ridge edges in direction of X axis + const auto add_ref_item_list_along_x = [&](const size_t j, const size_t k, const unsigned ref_id, + const std::string& ref_name) { + Array<EdgeId> boundary_edges(cell_size[0]); + size_t l = 0; + for (size_t i = 0; i < cell_size[0]; ++i) { + const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k}); + + auto i_edge = edge_to_id_map.find(Edge{{node_0_id, node_1_id}, descriptor.node_number_vector}); + Assert(i_edge != edge_to_id_map.end()); + + boundary_edges[l++] = i_edge->second; + } + Assert(l == cell_size[0]); + descriptor.addRefItemList(RefEdgeList{RefId{ref_id, ref_name}, boundary_edges}); + }; + + add_ref_item_list_along_x(0, 0, 28, "YMINZMIN"); + add_ref_item_list_along_x(0, cell_size[2], 29, "YMINZMAX"); + add_ref_item_list_along_x(cell_size[1], cell_size[2], 30, "YMAXZMAX"); + add_ref_item_list_along_x(cell_size[1], 0, 31, "YMAXZMIN"); + } +} + +template <size_t Dimension> +void +LogicalConnectivityBuilder::_buildBoundaryFaceList(const TinyVector<Dimension, uint64_t>&, ConnectivityDescriptor&) +{ + static_assert(Dimension >= 2 and Dimension <= 3, "unexpected dimension"); +} + +template <> +void +LogicalConnectivityBuilder::_buildBoundaryFaceList( + const TinyVector<2, uint64_t>& cell_size, // clazy:exclude=function-args-by-value + ConnectivityDescriptor& descriptor) +{ + const auto cell_number = [&](const TinyVector<2, uint64_t> cell_logic_id) { + return cell_logic_id[0] * cell_size[1] + cell_logic_id[1]; + }; + + { // xmin + const size_t i = 0; + Array<FaceId> boundary_faces(cell_size[1]); + for (size_t j = 0; j < cell_size[1]; ++j) { + constexpr size_t left_face = 3; + + const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); + const size_t face_id = descriptor.cell_to_face_vector[cell_id][left_face]; + + boundary_faces[j] = face_id; + } + descriptor.addRefItemList(RefFaceList{RefId{0, "XMIN"}, boundary_faces}); + } + + { // xmax + const size_t i = cell_size[0] - 1; + Array<FaceId> boundary_faces(cell_size[1]); + for (size_t j = 0; j < cell_size[1]; ++j) { + constexpr size_t right_face = 1; + + const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); + const size_t face_id = descriptor.cell_to_face_vector[cell_id][right_face]; + + boundary_faces[j] = face_id; + } + descriptor.addRefItemList(RefFaceList{RefId{1, "XMAX"}, boundary_faces}); + } + + { // ymin + const size_t j = 0; + Array<FaceId> boundary_faces(cell_size[0]); + for (size_t i = 0; i < cell_size[0]; ++i) { + constexpr size_t bottom_face = 0; + + const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); + const size_t face_id = descriptor.cell_to_face_vector[cell_id][bottom_face]; + + boundary_faces[i] = face_id; + } + descriptor.addRefItemList(RefFaceList{RefId{2, "YMIN"}, boundary_faces}); + } + + { // ymax + const size_t j = cell_size[1] - 1; + Array<FaceId> boundary_faces(cell_size[0]); + for (size_t i = 0; i < cell_size[0]; ++i) { + constexpr size_t top_face = 2; + + const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); + const size_t face_id = descriptor.cell_to_face_vector[cell_id][top_face]; + + boundary_faces[i] = face_id; + } + descriptor.addRefItemList(RefFaceList{RefId{3, "YMAX"}, boundary_faces}); + } +} + +template <> +void +LogicalConnectivityBuilder::_buildBoundaryFaceList(const TinyVector<3, uint64_t>& cell_size, + ConnectivityDescriptor& descriptor) +{ + using Face = ConnectivityFace<3>; + + const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { + std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; + for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { + const auto& node_vector = descriptor.face_to_node_vector[l]; + face_to_id_map[Face(node_vector, descriptor.node_number_vector)] = l; + } + return face_to_id_map; + }(); + + const std::unordered_map<int, FaceId> face_number_id_map = [&] { + std::unordered_map<int, FaceId> face_number_id_map; + for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { + face_number_id_map[descriptor.face_number_vector[l]] = l; + } + Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); + return face_number_id_map; + }(); + + const TinyVector<3, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1, cell_size[2] + 1}; + const auto node_number = [&](const TinyVector<3, uint64_t>& node_logic_id) { + return (node_logic_id[0] * node_size[1] + node_logic_id[1]) * node_size[2] + node_logic_id[2]; + }; + + { // faces orthogonal to X + const auto add_ref_item_list_for_x = [&](const size_t i, const unsigned ref_id, const std::string& ref_name) { + Array<FaceId> boundary_faces(cell_size[1] * cell_size[2]); + size_t l = 0; + for (size_t j = 0; j < cell_size[1]; ++j) { + for (size_t k = 0; k < cell_size[2]; ++k) { + const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k}); + const uint32_t node_2_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k + 1}); + const uint32_t node_3_id = node_number(TinyVector<3, uint64_t>{i, j, k + 1}); + + auto i_face = + face_to_id_map.find(Face{{node_0_id, node_1_id, node_2_id, node_3_id}, descriptor.node_number_vector}); + Assert(i_face != face_to_id_map.end()); + + boundary_faces[l++] = i_face->second; + } + } + Assert(l == cell_size[1] * cell_size[2]); + descriptor.addRefItemList(RefFaceList{RefId{ref_id, ref_name}, boundary_faces}); + }; + + add_ref_item_list_for_x(0, 0, "XMIN"); + add_ref_item_list_for_x(cell_size[0], 1, "XMAX"); + } + + { // faces orthogonal to Y + const auto add_ref_item_list_for_y = [&](const size_t j, const unsigned ref_id, const std::string& ref_name) { + Array<FaceId> boundary_faces(cell_size[0] * cell_size[2]); + size_t l = 0; + for (size_t i = 0; i < cell_size[0]; ++i) { + for (size_t k = 0; k < cell_size[2]; ++k) { + const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k}); + const uint32_t node_2_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k + 1}); + const uint32_t node_3_id = node_number(TinyVector<3, uint64_t>{i, j, k + 1}); + + auto i_face = + face_to_id_map.find(Face{{node_0_id, node_1_id, node_2_id, node_3_id}, descriptor.node_number_vector}); + Assert(i_face != face_to_id_map.end()); + + boundary_faces[l++] = i_face->second; + } + } + Assert(l == cell_size[0] * cell_size[2]); + descriptor.addRefItemList(RefFaceList{RefId{ref_id, ref_name}, boundary_faces}); + }; + + add_ref_item_list_for_y(0, 2, "YMIN"); + add_ref_item_list_for_y(cell_size[1], 3, "YMAX"); + } + + { // faces orthogonal to Z + const auto add_ref_item_list_for_z = [&](const size_t k, const unsigned ref_id, const std::string& ref_name) { + Array<FaceId> boundary_faces(cell_size[0] * cell_size[1]); + size_t l = 0; + for (size_t i = 0; i < cell_size[0]; ++i) { + for (size_t j = 0; j < cell_size[1]; ++j) { + const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k}); + const uint32_t node_2_id = node_number(TinyVector<3, uint64_t>{i + 1, j + 1, k}); + const uint32_t node_3_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k}); + + auto i_face = + face_to_id_map.find(Face{{node_0_id, node_1_id, node_2_id, node_3_id}, descriptor.node_number_vector}); + Assert(i_face != face_to_id_map.end()); + + boundary_faces[l++] = i_face->second; + } + } + Assert(l == cell_size[0] * cell_size[1]); + descriptor.addRefItemList(RefFaceList{RefId{ref_id, ref_name}, boundary_faces}); + }; + + add_ref_item_list_for_z(0, 4, "ZMIN"); + add_ref_item_list_for_z(cell_size[2], 5, "ZMAX"); + } +} + +template <> +void +LogicalConnectivityBuilder::_buildConnectivity( + const TinyVector<1, uint64_t>& cell_size) // clazy:exclude=function-args-by-value +{ + const size_t number_of_cells = cell_size[0]; + const size_t number_of_nodes = cell_size[0] + 1; + + ConnectivityDescriptor descriptor; + descriptor.node_number_vector.resize(number_of_nodes); + for (size_t i = 0; i < number_of_nodes; ++i) { + descriptor.node_number_vector[i] = i; + } + + descriptor.cell_number_vector.resize(number_of_cells); + for (size_t i = 0; i < number_of_cells; ++i) { + descriptor.cell_number_vector[i] = i; + } + + descriptor.cell_type_vector.resize(number_of_cells); + std::fill(descriptor.cell_type_vector.begin(), descriptor.cell_type_vector.end(), CellType::Line); + + descriptor.cell_to_node_vector.resize(number_of_cells); + constexpr size_t nb_node_per_cell = 2; + for (size_t j = 0; j < number_of_cells; ++j) { + descriptor.cell_to_node_vector[j].resize(nb_node_per_cell); + for (size_t r = 0; r < nb_node_per_cell; ++r) { + descriptor.cell_to_node_vector[j][0] = j; + descriptor.cell_to_node_vector[j][1] = j + 1; + } + } + + this->_buildBoundaryNodeList(cell_size, descriptor); + + descriptor.cell_owner_vector.resize(number_of_cells); + std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); + + descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); + std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + + m_connectivity = Connectivity1D::build(descriptor); +} + +template <> +void +LogicalConnectivityBuilder::_buildConnectivity( + const TinyVector<2, uint64_t>& cell_size) // clazy:exclude=function-args-by-value +{ + constexpr size_t Dimension = 2; + + const TinyVector<Dimension, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1}; + + const size_t number_of_cells = cell_size[0] * cell_size[1]; + const size_t number_of_nodes = node_size[0] * node_size[1]; + + ConnectivityDescriptor descriptor; + descriptor.node_number_vector.resize(number_of_nodes); + for (size_t i = 0; i < number_of_nodes; ++i) { + descriptor.node_number_vector[i] = i; + } + + descriptor.cell_number_vector.resize(number_of_cells); + for (size_t i = 0; i < number_of_cells; ++i) { + descriptor.cell_number_vector[i] = i; + } + + descriptor.cell_type_vector.resize(number_of_cells); + std::fill(descriptor.cell_type_vector.begin(), descriptor.cell_type_vector.end(), CellType::Quadrangle); + + const auto node_number = [&](const TinyVector<Dimension, uint64_t> node_logic_id) { + return node_logic_id[0] * node_size[1] + node_logic_id[1]; + }; + + const auto cell_logic_id = [&](size_t j) { + const uint64_t j0 = j / cell_size[1]; + const uint64_t j1 = j % cell_size[1]; + return TinyVector<Dimension, uint64_t>{j0, j1}; + }; + + descriptor.cell_to_node_vector.resize(number_of_cells); + constexpr size_t nb_node_per_cell = 1 << Dimension; + for (size_t j = 0; j < number_of_cells; ++j) { + TinyVector<Dimension, size_t> cell_index = cell_logic_id(j); + descriptor.cell_to_node_vector[j].resize(nb_node_per_cell); + for (size_t r = 0; r < nb_node_per_cell; ++r) { + descriptor.cell_to_node_vector[j][0] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0}); + descriptor.cell_to_node_vector[j][1] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0}); + descriptor.cell_to_node_vector[j][2] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1}); + descriptor.cell_to_node_vector[j][3] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1}); + } + } + + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<Dimension>(descriptor); + + this->_buildBoundaryNodeList(cell_size, descriptor); + this->_buildBoundaryFaceList(cell_size, descriptor); + + descriptor.cell_owner_vector.resize(number_of_cells); + std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); + + descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); + std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); + + descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); + std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + + m_connectivity = Connectivity<Dimension>::build(descriptor); +} + +template <> +void +LogicalConnectivityBuilder::_buildConnectivity(const TinyVector<3, uint64_t>& cell_size) +{ + constexpr size_t Dimension = 3; + + const TinyVector<Dimension, uint64_t> node_size = [&] { + TinyVector node_size{cell_size}; + for (size_t i = 0; i < Dimension; ++i) { + node_size[i] += 1; + } + return node_size; + }(); + + auto count_items = [](auto&& v) { + using V_Type = std::decay_t<decltype(v)>; + static_assert(is_tiny_vector_v<V_Type>); + + size_t sum = v[0]; + for (size_t i = 1; i < Dimension; ++i) { + sum *= v[i]; + } + return sum; + }; + + const size_t number_of_cells = count_items(cell_size); + const size_t number_of_nodes = count_items(node_size); + + ConnectivityDescriptor descriptor; + descriptor.node_number_vector.resize(number_of_nodes); + for (size_t i = 0; i < number_of_nodes; ++i) { + descriptor.node_number_vector[i] = i; + } + + descriptor.cell_number_vector.resize(number_of_cells); + for (size_t i = 0; i < number_of_cells; ++i) { + descriptor.cell_number_vector[i] = i; + } + + descriptor.cell_type_vector.resize(number_of_cells); + std::fill(descriptor.cell_type_vector.begin(), descriptor.cell_type_vector.end(), CellType::Hexahedron); + + const auto cell_logic_id = [&](size_t j) { + const size_t slice1 = cell_size[1] * cell_size[2]; + const size_t& slice2 = cell_size[2]; + const uint64_t j0 = j / slice1; + const uint64_t j1 = (j - j0 * slice1) / slice2; + const uint64_t j2 = j - (j0 * slice1 + j1 * slice2); + return TinyVector<Dimension, uint64_t>{j0, j1, j2}; + }; + + const auto node_number = [&](const TinyVector<Dimension, uint64_t>& node_logic_id) { + return (node_logic_id[0] * node_size[1] + node_logic_id[1]) * node_size[2] + node_logic_id[2]; + }; + + descriptor.cell_to_node_vector.resize(number_of_cells); + constexpr size_t nb_node_per_cell = 1 << Dimension; + for (size_t j = 0; j < number_of_cells; ++j) { + TinyVector<Dimension, size_t> cell_index = cell_logic_id(j); + descriptor.cell_to_node_vector[j].resize(nb_node_per_cell); + for (size_t r = 0; r < nb_node_per_cell; ++r) { + static_assert(Dimension == 3, "unexpected dimension"); + descriptor.cell_to_node_vector[j][0] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0, 0}); + descriptor.cell_to_node_vector[j][1] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0, 0}); + descriptor.cell_to_node_vector[j][2] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1, 0}); + descriptor.cell_to_node_vector[j][3] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1, 0}); + descriptor.cell_to_node_vector[j][4] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0, 1}); + descriptor.cell_to_node_vector[j][5] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0, 1}); + descriptor.cell_to_node_vector[j][6] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1, 1}); + descriptor.cell_to_node_vector[j][7] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1, 1}); + } + } + + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<Dimension>(descriptor); + ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<Dimension>(descriptor); + + this->_buildBoundaryNodeList(cell_size, descriptor); + this->_buildBoundaryEdgeList(cell_size, descriptor); + this->_buildBoundaryFaceList(cell_size, descriptor); + + descriptor.cell_owner_vector.resize(number_of_cells); + std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); + + descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); + std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); + + descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size()); + std::fill(descriptor.edge_owner_vector.begin(), descriptor.edge_owner_vector.end(), parallel::rank()); + + descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); + std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + + m_connectivity = Connectivity<Dimension>::build(descriptor); +} + +template <size_t Dimension> +LogicalConnectivityBuilder::LogicalConnectivityBuilder(const TinyVector<Dimension, uint64_t>& size) +{ + if (parallel::rank() == 0) { + this->_buildConnectivity(size); + } +} + +template LogicalConnectivityBuilder::LogicalConnectivityBuilder(const TinyVector<1, uint64_t>&); + +template LogicalConnectivityBuilder::LogicalConnectivityBuilder(const TinyVector<2, uint64_t>&); + +template LogicalConnectivityBuilder::LogicalConnectivityBuilder(const TinyVector<3, uint64_t>&); diff --git a/src/mesh/LogicalConnectivityBuilder.hpp b/src/mesh/LogicalConnectivityBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c63226dbfc35d97a575968a28cc7cee2bb5821ff --- /dev/null +++ b/src/mesh/LogicalConnectivityBuilder.hpp @@ -0,0 +1,29 @@ +#ifndef LOGICAL_CONNECTIVITY_BUILDER_HPP +#define LOGICAL_CONNECTIVITY_BUILDER_HPP + +#include <algebra/TinyVector.hpp> + +#include <mesh/ConnectivityBuilderBase.hpp> + +class LogicalConnectivityBuilder : public ConnectivityBuilderBase +{ + private: + template <size_t Dimension> + void _buildBoundaryNodeList(const TinyVector<Dimension, uint64_t>& cell_size, ConnectivityDescriptor& descriptor); + + template <size_t Dimension> + void _buildBoundaryEdgeList(const TinyVector<Dimension, uint64_t>& cell_size, ConnectivityDescriptor& descriptor); + + template <size_t Dimension> + void _buildBoundaryFaceList(const TinyVector<Dimension, uint64_t>& cell_size, ConnectivityDescriptor& descriptor); + + template <size_t Dimension> + void _buildConnectivity(const TinyVector<Dimension, uint64_t>& size); + + public: + template <size_t Dimension> + LogicalConnectivityBuilder(const TinyVector<Dimension, uint64_t>& size); + ~LogicalConnectivityBuilder() = default; +}; + +#endif // LOGICAL_CONNECTIVITY_BUILDER_HPP diff --git a/src/mesh/Mesh.hpp b/src/mesh/Mesh.hpp index 92ec018e9033d87b751b71e3b67d33888356878e..d04807650cd08c0b96a7259cbe5756596d54aad1 100644 --- a/src/mesh/Mesh.hpp +++ b/src/mesh/Mesh.hpp @@ -2,24 +2,12 @@ #define MESH_HPP #include <algebra/TinyVector.hpp> - +#include <mesh/IMesh.hpp> #include <mesh/ItemValue.hpp> #include <utils/CSRGraph.hpp> #include <memory> -struct IMesh -{ - public: - virtual size_t dimension() const = 0; - - IMesh(const IMesh&) = delete; - IMesh(IMesh&&) = delete; - - IMesh() = default; - ~IMesh() = default; -}; - template <typename ConnectivityType> class Mesh final : public IMesh { @@ -32,7 +20,6 @@ class Mesh final : public IMesh private: const std::shared_ptr<const Connectivity> m_connectivity; NodeValue<const Rd> m_xr; - NodeValue<Rd> m_mutable_xr; public: PUGS_INLINE @@ -49,6 +36,13 @@ class Mesh final : public IMesh return *m_connectivity; } + PUGS_INLINE + const auto& + shared_connectivity() const + { + return m_connectivity; + } + PUGS_INLINE size_t numberOfNodes() const @@ -77,16 +71,9 @@ class Mesh final : public IMesh return m_xr; } - PUGS_INLINE - NodeValue<Rd> - mutableXr() const - { - return m_mutable_xr; - } - PUGS_INLINE Mesh(const std::shared_ptr<const Connectivity>& connectivity, NodeValue<Rd>& xr) - : m_connectivity{connectivity}, m_xr{xr}, m_mutable_xr{xr} + : m_connectivity{connectivity}, m_xr{xr} { ; } diff --git a/src/mesh/MeshBuilderBase.cpp b/src/mesh/MeshBuilderBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e62baf56e7915379d65a5c88c21fe7411fca253 --- /dev/null +++ b/src/mesh/MeshBuilderBase.cpp @@ -0,0 +1,43 @@ +#include <mesh/MeshBuilderBase.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityDescriptor.hpp> +#include <mesh/ConnectivityDispatcher.hpp> +#include <mesh/ItemId.hpp> +#include <mesh/Mesh.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +#include <vector> + +template <int Dimension> +void +MeshBuilderBase::_dispatch() +{ + if (parallel::size() == 1) { + return; + } + + using ConnectivityType = Connectivity<Dimension>; + using Rd = TinyVector<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + if (not m_mesh) { + ConnectivityDescriptor descriptor; + std::shared_ptr connectivity = ConnectivityType::build(descriptor); + NodeValue<Rd> xr; + m_mesh = std::make_shared<MeshType>(connectivity, xr); + } + const MeshType& mesh = static_cast<const MeshType&>(*m_mesh); + + ConnectivityDispatcher<Dimension> dispatcher(mesh.connectivity()); + + std::shared_ptr dispatched_connectivity = dispatcher.dispatchedConnectivity(); + NodeValue<Rd> dispatched_xr = dispatcher.dispatch(mesh.xr()); + + m_mesh = std::make_shared<MeshType>(dispatched_connectivity, dispatched_xr); +} + +template void MeshBuilderBase::_dispatch<1>(); +template void MeshBuilderBase::_dispatch<2>(); +template void MeshBuilderBase::_dispatch<3>(); diff --git a/src/mesh/MeshBuilderBase.hpp b/src/mesh/MeshBuilderBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6c0328bb8ee624e19d42fb4660ba3665ff7164de --- /dev/null +++ b/src/mesh/MeshBuilderBase.hpp @@ -0,0 +1,27 @@ +#ifndef MESH_BUILDER_BASE_HPP +#define MESH_BUILDER_BASE_HPP + +#include <mesh/IMesh.hpp> + +#include <memory> + +class MeshBuilderBase +{ + protected: + std::shared_ptr<const IMesh> m_mesh; + + template <int Dimension> + void _dispatch(); + + public: + std::shared_ptr<const IMesh> + mesh() const + { + return m_mesh; + } + + MeshBuilderBase() = default; + ~MeshBuilderBase() = default; +}; + +#endif // MESH_BUILDER_BASE_HPP diff --git a/src/mesh/MeshData.hpp b/src/mesh/MeshData.hpp index 1647abc0b1fe9f8e29d3a5a6a230548fc8f799b9..01eccadce6fcedb1cfaea71d87e959781190cc25 100644 --- a/src/mesh/MeshData.hpp +++ b/src/mesh/MeshData.hpp @@ -2,21 +2,29 @@ #define MESH_DATA_HPP #include <algebra/TinyVector.hpp> -#include <utils/PugsUtils.hpp> - +#include <mesh/IMeshData.hpp> #include <mesh/ItemValue.hpp> #include <mesh/SubItemValuePerItem.hpp> +#include <utils/Exceptions.hpp> +#include <utils/Messenger.hpp> +#include <utils/PugsUtils.hpp> #include <map> -template <typename M> -class MeshData +template <size_t Dimension> +class Connectivity; + +template <typename ConnectivityType> +class Mesh; + +template <size_t Dimension> +class MeshData : public IMeshData { public: - using MeshType = M; - - static constexpr size_t Dimension = MeshType::Dimension; static_assert(Dimension > 0, "dimension must be strictly positive"); + static_assert((Dimension <= 3), "only 1d, 2d and 3d are implemented"); + + using MeshType = Mesh<Connectivity<Dimension>>; using Rd = TinyVector<Dimension>; @@ -24,15 +32,16 @@ class MeshData private: const MeshType& m_mesh; - NodeValuePerCell<const Rd> m_Cjr; - NodeValuePerCell<const double> m_ljr; - NodeValuePerCell<const Rd> m_njr; - CellValue<const Rd> m_xj; - CellValue<const double> m_Vj; + std::shared_ptr<NodeValuePerCell<const Rd>> m_Cjr; + std::shared_ptr<NodeValuePerCell<const double>> m_ljr; + std::shared_ptr<NodeValuePerCell<const Rd>> m_njr; + std::shared_ptr<CellValue<const Rd>> m_xj; + std::shared_ptr<CellValue<const double>> m_Vj; + std::shared_ptr<NodeValuePerFace<const Rd>> m_Nlr; PUGS_INLINE void - _updateCenter() + _computeIsobarycenter() { // Computes vertices isobarycenter if constexpr (Dimension == 1) { const NodeValue<const Rd>& xr = m_mesh.xr(); @@ -45,7 +54,7 @@ class MeshData const auto& cell_nodes = cell_to_node_matrix[j]; xj[j] = 0.5 * (xr[cell_nodes[0]] + xr[cell_nodes[1]]); }); - m_xj = xj; + m_xj = std::make_shared<CellValue<const Rd>>(xj); } else { const NodeValue<const Rd>& xr = m_mesh.xr(); @@ -62,17 +71,19 @@ class MeshData } xj[j] = inv_cell_nb_nodes[j] * X; }); - m_xj = xj; + m_xj = std::make_shared<CellValue<const Rd>>(xj); } } PUGS_INLINE void - _updateVolume() + _computeCellVolume() { const NodeValue<const Rd>& xr = m_mesh.xr(); const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + auto Cjr = this->Cjr(); + CellValue<double> Vj(m_mesh.connectivity()); parallel_for( m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { @@ -80,52 +91,22 @@ class MeshData const auto& cell_nodes = cell_to_node_matrix[j]; for (size_t R = 0; R < cell_nodes.size(); ++R) { - sum_cjr_xr += (xr[cell_nodes[R]], m_Cjr(j, R)); + sum_cjr_xr += (xr[cell_nodes[R]], Cjr(j, R)); } Vj[j] = inv_Dimension * sum_cjr_xr; }); - m_Vj = Vj; + m_Vj = std::make_shared<CellValue<const double>>(Vj); } PUGS_INLINE void - _updateCjr() + _computeNlr() { if constexpr (Dimension == 1) { - // Cjr/njr/ljr are constant overtime + static_assert(Dimension != 1, "Nlr does not make sense in 1d"); } else if constexpr (Dimension == 2) { - const NodeValue<const Rd>& xr = m_mesh.xr(); - const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); - - { - NodeValuePerCell<Rd> Cjr(m_mesh.connectivity()); - parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { - const auto& cell_nodes = cell_to_node_matrix[j]; - for (size_t R = 0; R < cell_nodes.size(); ++R) { - int Rp1 = (R + 1) % cell_nodes.size(); - int Rm1 = (R + cell_nodes.size() - 1) % cell_nodes.size(); - Rd half_xrp_xrm = 0.5 * (xr[cell_nodes[Rp1]] - xr[cell_nodes[Rm1]]); - Cjr(j, R) = Rd{-half_xrp_xrm[1], half_xrp_xrm[0]}; - } - }); - m_Cjr = Cjr; - } - - { - NodeValuePerCell<double> ljr(m_mesh.connectivity()); - parallel_for( - m_Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { ljr[jr] = l2Norm(m_Cjr[jr]); }); - m_ljr = ljr; - } - - { - NodeValuePerCell<Rd> njr(m_mesh.connectivity()); - parallel_for( - m_Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { njr[jr] = (1. / m_ljr[jr]) * m_Cjr[jr]; }); - m_njr = njr; - } - } else if (Dimension == 3) { + throw NotImplementedError("Nlr are not yet computed in 2d"); + } else { const NodeValue<const Rd>& xr = m_mesh.xr(); NodeValuePerFace<Rd> Nlr(m_mesh.connectivity()); @@ -151,70 +132,142 @@ class MeshData Nlr(l, r) = Nr; } }); + m_Nlr = std::make_shared<NodeValuePerFace<const Rd>>(Nlr); + } + } + PUGS_INLINE + void + _computeCjr() + { + if constexpr (Dimension == 1) { + NodeValuePerCell<Rd> Cjr(m_mesh.connectivity()); + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + Cjr(j, 0) = -1; + Cjr(j, 1) = 1; + }); + m_Cjr = std::make_shared<NodeValuePerCell<const Rd>>(Cjr); + } else if constexpr (Dimension == 2) { + const NodeValue<const Rd>& xr = m_mesh.xr(); const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); - const auto& cell_to_face_matrix = m_mesh.connectivity().cellToFaceMatrix(); + NodeValuePerCell<Rd> Cjr(m_mesh.connectivity()); + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + for (size_t R = 0; R < cell_nodes.size(); ++R) { + int Rp1 = (R + 1) % cell_nodes.size(); + int Rm1 = (R + cell_nodes.size() - 1) % cell_nodes.size(); + Rd half_xrp_xrm = 0.5 * (xr[cell_nodes[Rp1]] - xr[cell_nodes[Rm1]]); + Cjr(j, R) = Rd{half_xrp_xrm[1], -half_xrp_xrm[0]}; + } + }); + m_Cjr = std::make_shared<NodeValuePerCell<const Rd>>(Cjr); + } else if (Dimension == 3) { + auto Nlr = this->Nlr(); + const auto& face_to_node_matrix = m_mesh.connectivity().faceToNodeMatrix(); + const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_face_matrix = m_mesh.connectivity().cellToFaceMatrix(); const auto& cell_face_is_reversed = m_mesh.connectivity().cellFaceIsReversed(); - { - NodeValuePerCell<Rd> Cjr(m_mesh.connectivity()); - parallel_for( - Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { Cjr[jr] = zero; }); + NodeValuePerCell<Rd> Cjr(m_mesh.connectivity()); + parallel_for( + Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { Cjr[jr] = zero; }); - parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { - const auto& cell_nodes = cell_to_node_matrix[j]; + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; - const auto& cell_faces = cell_to_face_matrix[j]; - const auto& face_is_reversed = cell_face_is_reversed.itemValues(j); + const auto& cell_faces = cell_to_face_matrix[j]; + const auto& face_is_reversed = cell_face_is_reversed.itemValues(j); - for (size_t L = 0; L < cell_faces.size(); ++L) { - const FaceId& l = cell_faces[L]; - const auto& face_nodes = face_to_node_matrix[l]; + for (size_t L = 0; L < cell_faces.size(); ++L) { + const FaceId& l = cell_faces[L]; + const auto& face_nodes = face_to_node_matrix[l]; - auto local_node_number_in_cell = [&](NodeId node_number) { - for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { - if (node_number == cell_nodes[i_node]) { - return i_node; - } + auto local_node_number_in_cell = [&](NodeId node_number) { + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + if (node_number == cell_nodes[i_node]) { + return i_node; } - return std::numeric_limits<size_t>::max(); - }; + } + return std::numeric_limits<size_t>::max(); + }; - if (face_is_reversed[L]) { - for (size_t rl = 0; rl < face_nodes.size(); ++rl) { - const size_t R = local_node_number_in_cell(face_nodes[rl]); - Cjr(j, R) -= Nlr(l, rl); - } - } else { - for (size_t rl = 0; rl < face_nodes.size(); ++rl) { - const size_t R = local_node_number_in_cell(face_nodes[rl]); - Cjr(j, R) += Nlr(l, rl); - } + if (face_is_reversed[L]) { + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + const size_t R = local_node_number_in_cell(face_nodes[rl]); + Cjr(j, R) -= Nlr(l, rl); + } + } else { + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + const size_t R = local_node_number_in_cell(face_nodes[rl]); + Cjr(j, R) += Nlr(l, rl); } } - }); + } + }); - m_Cjr = Cjr; - } + m_Cjr = std::make_shared<NodeValuePerCell<const Rd>>(Cjr); + } + } - { - NodeValuePerCell<double> ljr(m_mesh.connectivity()); - parallel_for( - m_Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { ljr[jr] = l2Norm(m_Cjr[jr]); }); - m_ljr = ljr; - } + PUGS_INLINE + void + _compute_ljr() + { + auto Cjr = this->Cjr(); + if constexpr (Dimension == 1) { + NodeValuePerCell<double> ljr(m_mesh.connectivity()); + parallel_for( + ljr.numberOfValues(), PUGS_LAMBDA(size_t jr) { ljr[jr] = 1; }); + m_ljr = std::make_shared<NodeValuePerCell<const double>>(ljr); - { - NodeValuePerCell<Rd> njr(m_mesh.connectivity()); - parallel_for( - m_Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { njr[jr] = (1. / m_ljr[jr]) * m_Cjr[jr]; }); - m_njr = njr; + } else { + NodeValuePerCell<double> ljr(m_mesh.connectivity()); + parallel_for( + Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { ljr[jr] = l2Norm(Cjr[jr]); }); + m_ljr = std::make_shared<NodeValuePerCell<const double>>(ljr); + } + } + + PUGS_INLINE + void + _compute_njr() + { + auto Cjr = this->Cjr(); + if constexpr (Dimension == 1) { + // in 1d njr=Cjr (here performs a shallow copy) + m_njr = m_Cjr; + } else { + auto ljr = this->ljr(); + + NodeValuePerCell<Rd> njr(m_mesh.connectivity()); + parallel_for( + Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { njr[jr] = (1. / ljr[jr]) * Cjr[jr]; }); + m_njr = std::make_shared<NodeValuePerCell<const Rd>>(njr); + } + } + + void + _checkCellVolume() + { + auto Vj = this->Vj(); + + bool is_valid = [&] { + for (CellId j = 0; j < m_mesh.numberOfCells(); ++j) { + if (Vj[j] <= 0) { + return false; + } } + return true; + }(); + + if (not parallel::allReduceAnd(is_valid)) { + throw NormalError("mesh contains cells of non-positive volume"); } - static_assert((Dimension <= 3), "only 1d, 2d and 3d are implemented"); } public: @@ -226,75 +279,78 @@ class MeshData } PUGS_INLINE - const NodeValuePerCell<const Rd>& - Cjr() const + NodeValuePerFace<const Rd> + Nlr() { - return m_Cjr; + if (not m_Nlr) { + this->_computeNlr(); + } + return *m_Nlr; } PUGS_INLINE - const NodeValuePerCell<const double>& - ljr() const + NodeValuePerCell<const Rd> + Cjr() { - return m_ljr; + if (not m_Cjr) { + this->_computeCjr(); + } + return *m_Cjr; } PUGS_INLINE - const NodeValuePerCell<const Rd>& - njr() const + NodeValuePerCell<const double> + ljr() { - return m_njr; + if (not m_ljr) { + this->_compute_ljr(); + } + return *m_ljr; } PUGS_INLINE - const CellValue<const Rd>& - xj() const + NodeValuePerCell<const Rd> + njr() { - return m_xj; + if (not m_njr) { + this->_compute_njr(); + } + return *m_njr; } PUGS_INLINE - const CellValue<const double>& - Vj() const + CellValue<const Rd> + xj() { - return m_Vj; + if (not m_xj) { + this->_computeIsobarycenter(); + } + return *m_xj; } - void - updateAllData() + PUGS_INLINE + CellValue<const double> + Vj() { - this->_updateCjr(); - this->_updateCenter(); - this->_updateVolume(); + if (not m_Vj) { + this->_computeCellVolume(); + this->_checkCellVolume(); + } + return *m_Vj; } - MeshData(const MeshType& mesh) : m_mesh(mesh) + void + updateAllData() { - if constexpr (Dimension == 1) { - // in 1d Cjr are computed once for all - { - NodeValuePerCell<Rd> Cjr(m_mesh.connectivity()); - parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { - Cjr(j, 0) = -1; - Cjr(j, 1) = 1; - }); - m_Cjr = Cjr; - } - // in 1d njr=Cjr (here performs a shallow copy) - m_njr = m_Cjr; - { - NodeValuePerCell<double> ljr(m_mesh.connectivity()); - parallel_for( - ljr.numberOfValues(), PUGS_LAMBDA(size_t jr) { ljr[jr] = 1; }); - m_ljr = ljr; - } - } - this->updateAllData(); + ; } - MeshData(const MeshData&) = delete; - MeshData(MeshData&&) = delete; + MeshData(const MeshType& mesh) : m_mesh(mesh) {} + + MeshData() = delete; + + MeshData(const MeshData&) = default; + MeshData(MeshData&&) = default; ~MeshData() { diff --git a/src/mesh/MeshDataManager.cpp b/src/mesh/MeshDataManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae77ee8255f62447f8d49cd8f9a85a7aec6ddd10 --- /dev/null +++ b/src/mesh/MeshDataManager.cpp @@ -0,0 +1,61 @@ +#include <utils/PugsAssert.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> +#include <utils/Exceptions.hpp> + +#include <sstream> + +MeshDataManager* MeshDataManager::m_instance{nullptr}; + +void +MeshDataManager::create() +{ + Assert(m_instance == nullptr, "MeshDataManager is already created"); + m_instance = new MeshDataManager; +} + +void +MeshDataManager::destroy() +{ + Assert(m_instance != nullptr, "MeshDataManager was not created!"); + + if (m_instance->m_mesh_mesh_data_map.size() > 0) { + std::stringstream error; + error << ": some mesh data is still registered\n"; + for (const auto& i_connectivity_synchronizer : m_instance->m_mesh_mesh_data_map) { + error << " - mesh data " << rang::fgB::magenta << i_connectivity_synchronizer.first << rang::style::reset << '\n'; + } + throw UnexpectedError(error.str()); + } + delete m_instance; + m_instance = nullptr; +} + +void +MeshDataManager::deleteMeshData(const IMesh& mesh) +{ + m_mesh_mesh_data_map.erase(&mesh); +} + +template <size_t Dimension> +MeshData<Dimension>& +MeshDataManager::getMeshData(const Mesh<Connectivity<Dimension>>& mesh) +{ + const IMesh* p_mesh = &mesh; + + if (auto connectivity_synchronizer = m_mesh_mesh_data_map.find(p_mesh); + connectivity_synchronizer != m_mesh_mesh_data_map.end()) { + return dynamic_cast<MeshData<Dimension>&>(*connectivity_synchronizer->second); + } else { + std::shared_ptr mesh_data = std::make_shared<MeshData<Dimension>>(mesh); + m_mesh_mesh_data_map[p_mesh] = mesh_data; + return *mesh_data; + } +} + +template MeshData<1>& MeshDataManager::getMeshData(const Mesh<Connectivity<1>>&); +template MeshData<2>& MeshDataManager::getMeshData(const Mesh<Connectivity<2>>&); +template MeshData<3>& MeshDataManager::getMeshData(const Mesh<Connectivity<3>>&); diff --git a/src/mesh/MeshDataManager.hpp b/src/mesh/MeshDataManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7b127148b889bc585082d626b79c435293fa4cd7 --- /dev/null +++ b/src/mesh/MeshDataManager.hpp @@ -0,0 +1,53 @@ +#ifndef MESH_DATA_MANAGER_HPP +#define MESH_DATA_MANAGER_HPP + +#include <mesh/IMeshData.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +#include <map> +#include <memory> + +class IMesh; + +template <size_t> +class Connectivity; + +template <typename ConnectivityType> +class Mesh; + +template <size_t Dimension> +class MeshData; + +class MeshDataManager +{ + private: + std::map<const IMesh*, std::shared_ptr<IMeshData>> m_mesh_mesh_data_map; + + static MeshDataManager* m_instance; + + MeshDataManager(const MeshDataManager&) = delete; + MeshDataManager(MeshDataManager&&) = delete; + + MeshDataManager() = default; + ~MeshDataManager() = default; + + public: + static void create(); + static void destroy(); + + PUGS_INLINE + static MeshDataManager& + instance() + { + Assert(m_instance != nullptr, "MeshDataManager was not created!"); + return *m_instance; + } + + void deleteMeshData(const IMesh&); + + template <size_t Dimension> + MeshData<Dimension>& getMeshData(const Mesh<Connectivity<Dimension>>&); +}; + +#endif // MESH_DATA_MANAGER_HPP diff --git a/src/mesh/MeshNodeBoundary.hpp b/src/mesh/MeshNodeBoundary.hpp index e02c9b7520db65081977e4bb1774a348c9cd6e25..a49db8b4b358f52e7dd199a64a55a43b1123de2e 100644 --- a/src/mesh/MeshNodeBoundary.hpp +++ b/src/mesh/MeshNodeBoundary.hpp @@ -35,10 +35,10 @@ class MeshNodeBoundary // clazy:exclude=copyable-polymorphic } template <typename MeshType> - MeshNodeBoundary(const MeshType& mesh, const RefFaceList& ref_face_list) + MeshNodeBoundary(const std::shared_ptr<const MeshType>& mesh, const RefFaceList& ref_face_list) { static_assert(Dimension == MeshType::Dimension); - const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + const auto& face_to_cell_matrix = mesh->connectivity().faceToCellMatrix(); const Array<const FaceId>& face_list = ref_face_list.list(); parallel_for( @@ -52,7 +52,7 @@ class MeshNodeBoundary // clazy:exclude=copyable-polymorphic Kokkos::vector<unsigned int> node_ids; // not enough but should reduce significantly the number of resizing node_ids.reserve(Dimension * face_list.size()); - const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& face_to_node_matrix = mesh->connectivity().faceToNodeMatrix(); for (size_t l = 0; l < face_list.size(); ++l) { const FaceId face_number = face_list[l]; @@ -73,7 +73,8 @@ class MeshNodeBoundary // clazy:exclude=copyable-polymorphic } template <typename MeshType> - MeshNodeBoundary(const MeshType&, const RefNodeList& ref_node_list) : m_node_list(ref_node_list.list()) + MeshNodeBoundary(const std::shared_ptr<const MeshType>&, const RefNodeList& ref_node_list) + : m_node_list(ref_node_list.list()) { static_assert(Dimension == MeshType::Dimension); } @@ -96,16 +97,16 @@ class MeshFlatNodeBoundary : public MeshNodeBoundary<Dimension> // clazy:exclu const Rd m_outgoing_normal; template <typename MeshType> - PUGS_INLINE Rd _getNormal(const MeshType& mesh); + PUGS_INLINE Rd _getNormal(const std::shared_ptr<const MeshType>& mesh); template <typename MeshType> PUGS_INLINE void _checkBoundaryIsFlat(TinyVector<2, double> normal, TinyVector<2, double> xmin, TinyVector<2, double> xmax, - const MeshType& mesh) const; + const std::shared_ptr<const MeshType>& mesh) const; template <typename MeshType> - PUGS_INLINE Rd _getOutgoingNormal(const MeshType& mesh); + PUGS_INLINE Rd _getOutgoingNormal(const std::shared_ptr<const MeshType>& mesh); public: const Rd& @@ -118,14 +119,14 @@ class MeshFlatNodeBoundary : public MeshNodeBoundary<Dimension> // clazy:exclu MeshFlatNodeBoundary& operator=(MeshFlatNodeBoundary&&) = default; template <typename MeshType> - MeshFlatNodeBoundary(const MeshType& mesh, const RefFaceList& ref_face_list) + MeshFlatNodeBoundary(const std::shared_ptr<const MeshType>& mesh, const RefFaceList& ref_face_list) : MeshNodeBoundary<Dimension>(mesh, ref_face_list), m_outgoing_normal(_getOutgoingNormal(mesh)) { ; } template <typename MeshType> - MeshFlatNodeBoundary(const MeshType& mesh, const RefNodeList& ref_node_list) + MeshFlatNodeBoundary(const std::shared_ptr<const MeshType>& mesh, const RefNodeList& ref_node_list) : MeshNodeBoundary<Dimension>(mesh, ref_node_list), m_outgoing_normal(_getOutgoingNormal(mesh)) { ; @@ -143,7 +144,7 @@ void MeshFlatNodeBoundary<2>::_checkBoundaryIsFlat(TinyVector<2, double> normal, TinyVector<2, double> xmin, TinyVector<2, double> xmax, - const MeshType& mesh) const + const std::shared_ptr<const MeshType>& mesh) const { static_assert(MeshType::Dimension == 2); using R2 = TinyVector<2, double>; @@ -151,7 +152,7 @@ MeshFlatNodeBoundary<2>::_checkBoundaryIsFlat(TinyVector<2, double> normal, const R2 origin = 0.5 * (xmin + xmax); const double length = l2Norm(xmax - xmin); - const NodeValue<const R2>& xr = mesh.xr(); + const NodeValue<const R2>& xr = mesh->xr(); parallel_for( m_node_list.size(), PUGS_LAMBDA(size_t r) { @@ -165,14 +166,14 @@ MeshFlatNodeBoundary<2>::_checkBoundaryIsFlat(TinyVector<2, double> normal, template <> template <typename MeshType> PUGS_INLINE TinyVector<1, double> -MeshFlatNodeBoundary<1>::_getNormal(const MeshType& mesh) +MeshFlatNodeBoundary<1>::_getNormal(const std::shared_ptr<const MeshType>& mesh) { static_assert(MeshType::Dimension == 1); using R = TinyVector<1, double>; const size_t number_of_bc_nodes = [&]() { size_t number_of_bc_nodes = 0; - auto node_is_owned = mesh.connectivity().nodeIsOwned(); + auto node_is_owned = mesh->connectivity().nodeIsOwned(); for (size_t i_node = 0; i_node < m_node_list.size(); ++i_node) { number_of_bc_nodes += (node_is_owned[m_node_list[i_node]]); } @@ -189,12 +190,12 @@ MeshFlatNodeBoundary<1>::_getNormal(const MeshType& mesh) template <> template <typename MeshType> PUGS_INLINE TinyVector<2, double> -MeshFlatNodeBoundary<2>::_getNormal(const MeshType& mesh) +MeshFlatNodeBoundary<2>::_getNormal(const std::shared_ptr<const MeshType>& mesh) { static_assert(MeshType::Dimension == 2); using R2 = TinyVector<2, double>; - const NodeValue<const R2>& xr = mesh.xr(); + const NodeValue<const R2>& xr = mesh->xr(); R2 xmin(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); @@ -244,7 +245,7 @@ MeshFlatNodeBoundary<2>::_getNormal(const MeshType& mesh) template <> template <typename MeshType> PUGS_INLINE TinyVector<3, double> -MeshFlatNodeBoundary<3>::_getNormal(const MeshType& mesh) +MeshFlatNodeBoundary<3>::_getNormal(const std::shared_ptr<const MeshType>& mesh) { static_assert(MeshType::Dimension == 3); using R3 = TinyVector<3, double>; @@ -252,13 +253,12 @@ MeshFlatNodeBoundary<3>::_getNormal(const MeshType& mesh) R3 xmin(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); R3 ymin = xmin; R3 zmin = xmin; - ; R3 xmax = -xmin; R3 ymax = xmax; R3 zmax = xmax; - const NodeValue<const R3>& xr = mesh.xr(); + const NodeValue<const R3>& xr = mesh->xr(); for (size_t r = 0; r < m_node_list.size(); ++r) { const R3& x = xr[m_node_list[r]]; @@ -365,7 +365,7 @@ MeshFlatNodeBoundary<3>::_getNormal(const MeshType& mesh) template <> template <typename MeshType> PUGS_INLINE TinyVector<1, double> -MeshFlatNodeBoundary<1>::_getOutgoingNormal(const MeshType& mesh) +MeshFlatNodeBoundary<1>::_getOutgoingNormal(const std::shared_ptr<const MeshType>& mesh) { static_assert(MeshType::Dimension == 1); using R = TinyVector<1, double>; @@ -375,10 +375,10 @@ MeshFlatNodeBoundary<1>::_getOutgoingNormal(const MeshType& mesh) double max_height = 0; if (m_node_list.size() > 0) { - const NodeValue<const R>& xr = mesh.xr(); - const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const NodeValue<const R>& xr = mesh->xr(); + const auto& cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); - const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_to_cell_matrix = mesh->connectivity().nodeToCellMatrix(); const NodeId r0 = m_node_list[0]; const CellId j0 = node_to_cell_matrix[r0][0]; @@ -410,7 +410,7 @@ MeshFlatNodeBoundary<1>::_getOutgoingNormal(const MeshType& mesh) template <> template <typename MeshType> PUGS_INLINE TinyVector<2, double> -MeshFlatNodeBoundary<2>::_getOutgoingNormal(const MeshType& mesh) +MeshFlatNodeBoundary<2>::_getOutgoingNormal(const std::shared_ptr<const MeshType>& mesh) { static_assert(MeshType::Dimension == 2); using R2 = TinyVector<2, double>; @@ -420,10 +420,10 @@ MeshFlatNodeBoundary<2>::_getOutgoingNormal(const MeshType& mesh) double max_height = 0; if (m_node_list.size() > 0) { - const NodeValue<const R2>& xr = mesh.xr(); - const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const NodeValue<const R2>& xr = mesh->xr(); + const auto& cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); - const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_to_cell_matrix = mesh->connectivity().nodeToCellMatrix(); const NodeId r0 = m_node_list[0]; const CellId j0 = node_to_cell_matrix[r0][0]; @@ -454,7 +454,7 @@ MeshFlatNodeBoundary<2>::_getOutgoingNormal(const MeshType& mesh) template <> template <typename MeshType> PUGS_INLINE TinyVector<3, double> -MeshFlatNodeBoundary<3>::_getOutgoingNormal(const MeshType& mesh) +MeshFlatNodeBoundary<3>::_getOutgoingNormal(const std::shared_ptr<const MeshType>& mesh) { static_assert(MeshType::Dimension == 3); using R3 = TinyVector<3, double>; @@ -464,10 +464,10 @@ MeshFlatNodeBoundary<3>::_getOutgoingNormal(const MeshType& mesh) double max_height = 0; if (m_node_list.size() > 0) { - const NodeValue<const R3>& xr = mesh.xr(); - const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const NodeValue<const R3>& xr = mesh->xr(); + const auto& cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); - const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_to_cell_matrix = mesh->connectivity().nodeToCellMatrix(); const NodeId r0 = m_node_list[0]; const CellId j0 = node_to_cell_matrix[r0][0]; diff --git a/src/mesh/SubItemValuePerItem.hpp b/src/mesh/SubItemValuePerItem.hpp index b43a779c7d6accfd510a22432ed15374fd194b39..9ce6369e07b63537ac698149703547aa107e83cd 100644 --- a/src/mesh/SubItemValuePerItem.hpp +++ b/src/mesh/SubItemValuePerItem.hpp @@ -1,19 +1,13 @@ #ifndef SUBITEM_VALUE_PER_ITEM_HPP #define SUBITEM_VALUE_PER_ITEM_HPP -#include <Kokkos_StaticCrsGraph.hpp> - -#include <utils/PugsAssert.hpp> - -#include <utils/Array.hpp> - -#include <mesh/ItemId.hpp> - #include <mesh/ConnectivityMatrix.hpp> #include <mesh/IConnectivity.hpp> - +#include <mesh/ItemId.hpp> #include <mesh/ItemOfItemType.hpp> #include <mesh/ItemType.hpp> +#include <utils/Array.hpp> +#include <utils/PugsAssert.hpp> #include <memory> diff --git a/src/mesh/SynchronizerManager.cpp b/src/mesh/SynchronizerManager.cpp index 8e2346c793053bd4e8799978542eda2d6e554dc7..b1301bd88a341cae40c348e1239f673636f5b818 100644 --- a/src/mesh/SynchronizerManager.cpp +++ b/src/mesh/SynchronizerManager.cpp @@ -5,14 +5,6 @@ SynchronizerManager* SynchronizerManager::m_instance{nullptr}; -SynchronizerManager::~SynchronizerManager() -{ - if (m_connectivity_synchronizer_map.size() > 0) { - std::cerr << __FILE__ << ':' << __LINE__ << ": warning: some connectivities are still registered\n"; - ; - } -} - void SynchronizerManager::create() { @@ -24,6 +16,16 @@ void SynchronizerManager::destroy() { Assert(m_instance != nullptr, "SynchronizerManager was not created!"); + + if (m_instance->m_connectivity_synchronizer_map.size() > 0) { + std::stringstream error; + error << ": some connectivities are still registered\n"; + for (const auto& i_connectivity_synchronizer : m_instance->m_connectivity_synchronizer_map) { + error << " - connectivity " << rang::fgB::magenta << i_connectivity_synchronizer.first << rang::style::reset + << '\n'; + } + throw UnexpectedError(error.str()); + } delete m_instance; m_instance = nullptr; } diff --git a/src/mesh/SynchronizerManager.hpp b/src/mesh/SynchronizerManager.hpp index e0e4519c1dd339cd7c67a5dbbeac4f49bf120a7c..79cb3db0a3473bdbe9f88d4d20836a835aca9260 100644 --- a/src/mesh/SynchronizerManager.hpp +++ b/src/mesh/SynchronizerManager.hpp @@ -18,10 +18,10 @@ class SynchronizerManager static SynchronizerManager* m_instance; SynchronizerManager(const SynchronizerManager&) = delete; - SynchronizerManager(SynchronizerManager&) = delete; + SynchronizerManager(SynchronizerManager&&) = delete; - SynchronizerManager() = default; - ~SynchronizerManager(); + SynchronizerManager() = default; + ~SynchronizerManager() = default; public: static void create(); diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp index 7e818bec46b799ff0acf113230db894890141d78..5d85b3630e2afc77ef7f2a3422b2f7d207abe5b7 100644 --- a/src/output/VTKWriter.hpp +++ b/src/output/VTKWriter.hpp @@ -199,7 +199,7 @@ class VTKWriter public: template <typename MeshType> void - write(const MeshType& mesh, + write(const std::shared_ptr<const MeshType>& mesh, const OutputNamedItemValueSet& output_named_item_value_set, double time, bool forced_output = false) @@ -262,7 +262,7 @@ class VTKWriter fout << "<?xml version=\"1.0\"?>\n"; fout << "<VTKFile type=\"UnstructuredGrid\">\n"; fout << "<UnstructuredGrid>\n"; - fout << "<Piece NumberOfPoints=\"" << mesh.numberOfNodes() << "\" NumberOfCells=\"" << mesh.numberOfCells() + fout << "<Piece NumberOfPoints=\"" << mesh->numberOfNodes() << "\" NumberOfCells=\"" << mesh->numberOfCells() << "\">\n"; fout << "<CellData>\n"; for (const auto& [name, item_value_variant] : output_named_item_value_set) { @@ -279,10 +279,10 @@ class VTKWriter fout << "<Points>\n"; { using Rd = TinyVector<MeshType::Dimension>; - const NodeValue<const Rd>& xr = mesh.xr(); - Array<TinyVector<3>> positions(mesh.numberOfNodes()); + const NodeValue<const Rd>& xr = mesh->xr(); + Array<TinyVector<3>> positions(mesh->numberOfNodes()); parallel_for( - mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { for (unsigned short i = 0; i < MeshType::Dimension; ++i) { positions[r][i] = xr[r][i]; } @@ -296,16 +296,16 @@ class VTKWriter fout << "<Cells>\n"; { - const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); _write_array(fout, "connectivity", cell_to_node_matrix.entries()); } { - const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); - Array<unsigned int> offsets(mesh.numberOfCells()); + const auto& cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); + Array<unsigned int> offsets(mesh->numberOfCells()); unsigned int offset = 0; - for (CellId j = 0; j < mesh.numberOfCells(); ++j) { + for (CellId j = 0; j < mesh->numberOfCells(); ++j) { const auto& cell_nodes = cell_to_node_matrix[j]; offset += cell_nodes.size(); offsets[j] = offset; @@ -314,10 +314,10 @@ class VTKWriter } { - Array<int8_t> types(mesh.numberOfCells()); - const auto& cell_type = mesh.connectivity().cellType(); + Array<int8_t> types(mesh->numberOfCells()); + const auto& cell_type = mesh->connectivity().cellType(); parallel_for( - mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { switch (cell_type[j]) { case CellType::Line: { types[j] = 3; diff --git a/src/scheme/AcousticSolver.hpp b/src/scheme/AcousticSolver.hpp index fd10ea3203b02cf624cc0ff0b5a556517ba84512..971c8fd2458c35d55013a084a4919d7dce026ad6 100644 --- a/src/scheme/AcousticSolver.hpp +++ b/src/scheme/AcousticSolver.hpp @@ -13,6 +13,7 @@ #include <mesh/Mesh.hpp> #include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> @@ -25,19 +26,18 @@ #include <iostream> -template <typename MeshData> +template <typename MeshType> class AcousticSolver { - using MeshType = typename MeshData::MeshType; - using UnknownsType = FiniteVolumesEulerUnknowns<MeshData>; + constexpr static size_t Dimension = MeshType::Dimension; + + using MeshDataType = MeshData<Dimension>; + using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>; - MeshData& m_mesh_data; - const MeshType& m_mesh; + std::shared_ptr<const MeshType> m_mesh; const typename MeshType::Connectivity& m_connectivity; const std::vector<BoundaryConditionHandler>& m_boundary_condition_list; - constexpr static size_t Dimension = MeshType::Dimension; - using Rd = TinyVector<Dimension>; using Rdd = TinyMatrix<Dimension>; @@ -47,7 +47,7 @@ class AcousticSolver computeRhoCj(const CellValue<const double>& rhoj, const CellValue<const double>& cj) { parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { m_rhocj[j] = rhoj[j] * cj[j]; }); + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { m_rhocj[j] = rhoj[j] * cj[j]; }); return m_rhocj; } @@ -59,7 +59,7 @@ class AcousticSolver const NodeValuePerCell<const Rd>& njr) { parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { const size_t& nb_nodes = m_Ajr.numberOfSubValues(j); const double& rho_c = rhocj[j]; for (size_t r = 0; r < nb_nodes; ++r) { @@ -76,7 +76,7 @@ class AcousticSolver const auto& node_local_numbers_in_their_cells = m_connectivity.nodeLocalNumbersInTheirCells(); parallel_for( - m_mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + m_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { Rdd sum = zero; const auto& node_to_cell = node_to_cell_matrix[r]; const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemValues(r); @@ -103,7 +103,7 @@ class AcousticSolver const auto& node_local_numbers_in_their_cells = m_connectivity.nodeLocalNumbersInTheirCells(); parallel_for( - m_mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + m_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { Rd& br = m_br[r]; br = zero; const auto& node_to_cell = node_to_cell_matrix[r]; @@ -161,7 +161,7 @@ class AcousticSolver inverse(Ar, m_inv_Ar); const NodeValue<const Rdd> invAr = m_inv_Ar; parallel_for( - m_mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { m_ur[r] = invAr[r] * br[r]; }); + m_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { m_ur[r] = invAr[r] * br[r]; }); return m_ur; } @@ -173,10 +173,10 @@ class AcousticSolver const CellValue<const Rd>& uj, const CellValue<const double>& pj) { - const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_node_matrix = m_mesh->connectivity().cellToNodeMatrix(); parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { const auto& cell_nodes = cell_to_node_matrix[j]; for (size_t r = 0; r < cell_nodes.size(); ++r) { @@ -189,7 +189,7 @@ class AcousticSolver inverse(const NodeValue<const Rdd>& A, NodeValue<Rdd>& inv_A) const { parallel_for( - m_mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { inv_A[r] = ::inverse(A[r]); }); + m_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { inv_A[r] = ::inverse(A[r]); }); } PUGS_INLINE @@ -229,10 +229,9 @@ class AcousticSolver CellValue<double> m_Vj_over_cj; public: - AcousticSolver(MeshData& mesh_data, const std::vector<BoundaryConditionHandler>& bc_list) - : m_mesh_data(mesh_data), - m_mesh(mesh_data.mesh()), - m_connectivity(m_mesh.connectivity()), + AcousticSolver(std::shared_ptr<const MeshType> p_mesh, const std::vector<BoundaryConditionHandler>& bc_list) + : m_mesh(p_mesh), + m_connectivity(m_mesh->connectivity()), m_boundary_condition_list(bc_list), m_br(m_connectivity), m_Ajr(m_connectivity), @@ -250,11 +249,13 @@ class AcousticSolver double acoustic_dt(const CellValue<const double>& Vj, const CellValue<const double>& cj) const { - const NodeValuePerCell<const double>& ljr = m_mesh_data.ljr(); - const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); + + const NodeValuePerCell<const double>& ljr = mesh_data.ljr(); + const auto& cell_to_node_matrix = m_mesh->connectivity().cellToNodeMatrix(); parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { const auto& cell_nodes = cell_to_node_matrix[j]; double S = 0; @@ -267,8 +268,8 @@ class AcousticSolver return min(m_Vj_over_cj); } - void - computeNextStep(double, double dt, UnknownsType& unknowns) + [[nodiscard]] std::shared_ptr<const MeshType> + computeNextStep(double dt, UnknownsType& unknowns) { CellValue<double>& rhoj = unknowns.rhoj(); CellValue<Rd>& uj = unknowns.uj(); @@ -278,20 +279,22 @@ class AcousticSolver CellValue<double>& pj = unknowns.pj(); CellValue<double>& cj = unknowns.cj(); - const CellValue<const double>& Vj = m_mesh_data.Vj(); - const NodeValuePerCell<const Rd>& Cjr = m_mesh_data.Cjr(); - const NodeValuePerCell<const double>& ljr = m_mesh_data.ljr(); - const NodeValuePerCell<const Rd>& njr = m_mesh_data.njr(); + MeshData<Dimension>& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); + + const CellValue<const double> Vj = mesh_data.Vj(); + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const double> ljr = mesh_data.ljr(); + const NodeValuePerCell<const Rd> njr = mesh_data.njr(); computeExplicitFluxes(rhoj, uj, pj, cj, Cjr, ljr, njr); const NodeValuePerCell<Rd>& Fjr = m_Fjr; const NodeValue<const Rd> ur = m_ur; - const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_node_matrix = m_mesh->connectivity().cellToNodeMatrix(); const CellValue<const double> inv_mj = unknowns.invMj(); parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { const auto& cell_nodes = cell_to_node_matrix[j]; Rd momentum_fluxes = zero; @@ -306,16 +309,22 @@ class AcousticSolver }); parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { ej[j] = Ej[j] - 0.5 * (uj[j], uj[j]); }); + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { ej[j] = Ej[j] - 0.5 * (uj[j], uj[j]); }); - NodeValue<Rd> mutable_xr = m_mesh.mutableXr(); + NodeValue<Rd> new_xr = copy(m_mesh->xr()); parallel_for( - m_mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { mutable_xr[r] += dt * ur[r]; }); - m_mesh_data.updateAllData(); + m_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { new_xr[r] += dt * ur[r]; }); + + MeshDataManager::instance().getMeshData(*m_mesh).updateAllData(); + + m_mesh = std::make_shared<MeshType>(m_mesh->shared_connectivity(), new_xr); + CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*m_mesh).Vj(); const CellValue<const double> mj = unknowns.mj(); parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { rhoj[j] = mj[j] / Vj[j]; }); + m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { rhoj[j] = mj[j] / new_Vj[j]; }); + + return m_mesh; } }; diff --git a/src/scheme/BoundaryConditionDescriptor.hpp b/src/scheme/BoundaryConditionDescriptor.hpp deleted file mode 100644 index 8f4911ad940c56b335fabb1e002582f5d61ddd34..0000000000000000000000000000000000000000 --- a/src/scheme/BoundaryConditionDescriptor.hpp +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef BOUNDARY_CONDITION_DESCRIPTOR_HPP -#define BOUNDARY_CONDITION_DESCRIPTOR_HPP - -#include <mesh/RefId.hpp> - -#include <memory> - -class BoundaryDescriptor -{ - public: - enum class Type - { - named, - numbered - }; - - protected: - virtual std::ostream& _write(std::ostream& os) const = 0; - - public: - friend std::ostream& - operator<<(std::ostream& os, const BoundaryDescriptor& bd) - { - return bd._write(os); - } - - virtual bool operator==(const RefId& ref_id) const = 0; - friend bool - operator==(const RefId& ref_id, const BoundaryDescriptor& bcd) - { - return bcd == ref_id; - } - virtual Type type() const = 0; - - BoundaryDescriptor(const BoundaryDescriptor&) = delete; - BoundaryDescriptor(BoundaryDescriptor&&) = delete; - BoundaryDescriptor() = default; - - virtual ~BoundaryDescriptor() = default; -}; - -class NamedBoundaryDescriptor : public BoundaryDescriptor -{ - private: - std::string m_name; - - std::ostream& - _write(std::ostream& os) const final - { - os << '"' << m_name << '"'; - return os; - } - - public: - bool - operator==(const RefId& ref_id) const final - { - return m_name == ref_id.tagName(); - } - - Type - type() const final - { - return Type::named; - } - - NamedBoundaryDescriptor(const NamedBoundaryDescriptor&) = delete; - NamedBoundaryDescriptor(NamedBoundaryDescriptor&&) = delete; - NamedBoundaryDescriptor(const std::string& name) : m_name(name) - { - ; - } - virtual ~NamedBoundaryDescriptor() = default; -}; - -class NumberedBoundaryDescriptor : public BoundaryDescriptor -{ - private: - unsigned int m_number; - - std::ostream& - _write(std::ostream& os) const final - { - os << '"' << m_number << '"'; - return os; - } - - bool - operator==(const RefId& ref_id) const final - { - return m_number == ref_id.tagNumber(); - } - - public: - Type - type() const final - { - return Type::numbered; - } - - NumberedBoundaryDescriptor(const NumberedBoundaryDescriptor&) = delete; - NumberedBoundaryDescriptor(NumberedBoundaryDescriptor&&) = delete; - NumberedBoundaryDescriptor(unsigned int number) : m_number(number) - { - ; - } - virtual ~NumberedBoundaryDescriptor() = default; -}; - -class BoundaryConditionDescriptor -{ - public: - enum class Type - { - symmetry - }; - - protected: - std::shared_ptr<BoundaryDescriptor> m_boundary_descriptor; - - virtual std::ostream& _write(std::ostream& os) const = 0; - - public: - friend std::ostream& - operator<<(std::ostream& os, const BoundaryConditionDescriptor& bcd) - { - return bcd._write(os); - } - - virtual Type type() const = 0; - - const BoundaryDescriptor& - boundaryDescriptor() const - { - return *m_boundary_descriptor; - } - - BoundaryConditionDescriptor(std::shared_ptr<BoundaryDescriptor> boundary_descriptor) - : m_boundary_descriptor(boundary_descriptor) - { - ; - } - - BoundaryConditionDescriptor(const BoundaryConditionDescriptor&) = delete; - BoundaryConditionDescriptor(BoundaryConditionDescriptor&&) = delete; - - virtual ~BoundaryConditionDescriptor() = default; -}; - -class SymmetryBoundaryConditionDescriptor : public BoundaryConditionDescriptor -{ - private: - std::ostream& - _write(std::ostream& os) const final - { - os << "symmetry(" << *m_boundary_descriptor << ")"; - return os; - } - - public: - Type - type() const final - { - return Type::symmetry; - } - - SymmetryBoundaryConditionDescriptor(std::shared_ptr<BoundaryDescriptor> boundary_descriptor) - : BoundaryConditionDescriptor(boundary_descriptor) - { - ; - } - - SymmetryBoundaryConditionDescriptor(const SymmetryBoundaryConditionDescriptor&) = delete; - SymmetryBoundaryConditionDescriptor(SymmetryBoundaryConditionDescriptor&&) = delete; - - ~SymmetryBoundaryConditionDescriptor() = default; -}; - -#endif // BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/src/scheme/FiniteVolumesEulerUnknowns.hpp b/src/scheme/FiniteVolumesEulerUnknowns.hpp index a3fd012de3d0ea44fd8b0cfe724238bb115fa05c..406bc571c20729c49cfc26b90d436d438ebf3a15 100644 --- a/src/scheme/FiniteVolumesEulerUnknowns.hpp +++ b/src/scheme/FiniteVolumesEulerUnknowns.hpp @@ -16,7 +16,7 @@ class FiniteVolumesEulerUnknowns using Rd = TinyVector<Dimension>; private: - const MeshDataType& m_mesh_data; + MeshDataType& m_mesh_data; const MeshType& m_mesh; CellValue<double> m_rhoj; @@ -182,7 +182,7 @@ class FiniteVolumesEulerUnknowns m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { m_inv_mj[j] = 1. / m_mj[j]; }); } - FiniteVolumesEulerUnknowns(const MeshDataType& mesh_data) + FiniteVolumesEulerUnknowns(MeshDataType& mesh_data) : m_mesh_data(mesh_data), m_mesh(m_mesh_data.mesh()), m_rhoj(m_mesh.connectivity()), diff --git a/src/scheme/IBoundaryConditionDescriptor.hpp b/src/scheme/IBoundaryConditionDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0814c9e8580f6c36ad1152c3143d5877bff45dbc --- /dev/null +++ b/src/scheme/IBoundaryConditionDescriptor.hpp @@ -0,0 +1,33 @@ +#ifndef I_BOUNDARY_CONDITION_DESCRIPTOR_HPP +#define I_BOUNDARY_CONDITION_DESCRIPTOR_HPP + +#include <iostream> + +class IBoundaryConditionDescriptor +{ + public: + enum class Type + { + symmetry + }; + + protected: + virtual std::ostream& _write(std::ostream& os) const = 0; + + public: + friend std::ostream& + operator<<(std::ostream& os, const IBoundaryConditionDescriptor& bcd) + { + return bcd._write(os); + } + + virtual Type type() const = 0; + + IBoundaryConditionDescriptor() = default; + IBoundaryConditionDescriptor(const IBoundaryConditionDescriptor&) = delete; + IBoundaryConditionDescriptor(IBoundaryConditionDescriptor&&) = delete; + + virtual ~IBoundaryConditionDescriptor() = default; +}; + +#endif // I_BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/src/scheme/IBoundaryDescriptor.hpp b/src/scheme/IBoundaryDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4e016c35b6e13204fee2cbc23cf9bedf1d6ca4c7 --- /dev/null +++ b/src/scheme/IBoundaryDescriptor.hpp @@ -0,0 +1,41 @@ +#ifndef I_BOUNDARY_DESCRIPTOR_HPP +#define I_BOUNDARY_DESCRIPTOR_HPP + +#include <mesh/RefId.hpp> + +#include <iostream> + +class IBoundaryDescriptor +{ + public: + enum class Type + { + named, + numbered + }; + + protected: + virtual std::ostream& _write(std::ostream& os) const = 0; + + public: + friend std::ostream& + operator<<(std::ostream& os, const IBoundaryDescriptor& bd) + { + return bd._write(os); + } + + virtual bool operator==(const RefId& ref_id) const = 0; + friend bool + operator==(const RefId& ref_id, const IBoundaryDescriptor& bcd) + { + return bcd == ref_id; + } + virtual Type type() const = 0; + + IBoundaryDescriptor(const IBoundaryDescriptor&) = delete; + IBoundaryDescriptor(IBoundaryDescriptor&&) = delete; + IBoundaryDescriptor() = default; + + virtual ~IBoundaryDescriptor() = default; +}; +#endif // I_BOUNDARY_DESCRIPTOR_HPP diff --git a/src/scheme/NamedBoundaryDescriptor.hpp b/src/scheme/NamedBoundaryDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..db88ee4a0dd9ac39c65ff7b1a181d3c6aad262b4 --- /dev/null +++ b/src/scheme/NamedBoundaryDescriptor.hpp @@ -0,0 +1,43 @@ +#ifndef NAMED_BOUNDARY_DESCRIPTOR_HPP +#define NAMED_BOUNDARY_DESCRIPTOR_HPP + +#include <scheme/IBoundaryDescriptor.hpp> + +#include <iostream> +#include <string> + +class NamedBoundaryDescriptor : public IBoundaryDescriptor +{ + private: + std::string m_name; + + std::ostream& + _write(std::ostream& os) const final + { + os << '"' << m_name << '"'; + return os; + } + + public: + bool + operator==(const RefId& ref_id) const final + { + return m_name == ref_id.tagName(); + } + + Type + type() const final + { + return Type::named; + } + + NamedBoundaryDescriptor(const NamedBoundaryDescriptor&) = delete; + NamedBoundaryDescriptor(NamedBoundaryDescriptor&&) = delete; + NamedBoundaryDescriptor(const std::string& name) : m_name(name) + { + ; + } + virtual ~NamedBoundaryDescriptor() = default; +}; + +#endif // NAMED_BOUNDARY_DESCRIPTOR_HPP diff --git a/src/scheme/NumberedBoundaryDescriptor.hpp b/src/scheme/NumberedBoundaryDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4ed9a262859762a4103582fef57b642c82820d11 --- /dev/null +++ b/src/scheme/NumberedBoundaryDescriptor.hpp @@ -0,0 +1,42 @@ +#ifndef NUMBERED_BOUNDARY_DESCRIPTOR_HPP +#define NUMBERED_BOUNDARY_DESCRIPTOR_HPP + +#include <scheme/IBoundaryDescriptor.hpp> + +#include <iostream> + +class NumberedBoundaryDescriptor : public IBoundaryDescriptor +{ + private: + unsigned int m_number; + + std::ostream& + _write(std::ostream& os) const final + { + os << '"' << m_number << '"'; + return os; + } + + bool + operator==(const RefId& ref_id) const final + { + return m_number == ref_id.tagNumber(); + } + + public: + Type + type() const final + { + return Type::numbered; + } + + NumberedBoundaryDescriptor(const NumberedBoundaryDescriptor&) = delete; + NumberedBoundaryDescriptor(NumberedBoundaryDescriptor&&) = delete; + NumberedBoundaryDescriptor(unsigned int number) : m_number(number) + { + ; + } + virtual ~NumberedBoundaryDescriptor() = default; +}; + +#endif // NUMBERED_BOUNDARY_DESCRIPTOR_HPP diff --git a/src/scheme/SymmetryBoundaryConditionDescriptor.hpp b/src/scheme/SymmetryBoundaryConditionDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f5657ad58856f38c5d645501a14b62e77039b4c1 --- /dev/null +++ b/src/scheme/SymmetryBoundaryConditionDescriptor.hpp @@ -0,0 +1,46 @@ +#ifndef SYMMETRY_BOUNDARY_CONDITION_DESCRIPTOR_HPP +#define SYMMETRY_BOUNDARY_CONDITION_DESCRIPTOR_HPP + +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> + +#include <memory> + +class SymmetryBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +{ + private: + std::ostream& + _write(std::ostream& os) const final + { + os << "symmetry(" << *m_boundary_descriptor << ")"; + return os; + } + + std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; + + public: + const IBoundaryDescriptor& + boundaryDescriptor() const + { + return *m_boundary_descriptor; + } + + Type + type() const final + { + return Type::symmetry; + } + + SymmetryBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) + : m_boundary_descriptor(boundary_descriptor) + { + ; + } + + SymmetryBoundaryConditionDescriptor(const SymmetryBoundaryConditionDescriptor&) = delete; + SymmetryBoundaryConditionDescriptor(SymmetryBoundaryConditionDescriptor&&) = delete; + + ~SymmetryBoundaryConditionDescriptor() = default; +}; + +#endif // SYMMETRY_BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/src/utils/BacktraceManager.cpp b/src/utils/BacktraceManager.cpp index a07f34d572947ef709e565a86c52a07fb6247d94..26219cbd7b0eb3eb6a451e3ba0587af14445676a 100644 --- a/src/utils/BacktraceManager.cpp +++ b/src/utils/BacktraceManager.cpp @@ -1,11 +1,11 @@ #include <utils/BacktraceManager.hpp> -#include <iomanip> -#include <rang.hpp> +#include <utils/Demangle.hpp> #include <cmath> -#include <cxxabi.h> #include <execinfo.h> +#include <iomanip> +#include <rang.hpp> #include <regex> BacktraceManager::BacktraceManager() @@ -35,7 +35,6 @@ operator<<(std::ostream& os, const BacktraceManager& btm) const auto& line = lines[i_line]; os << rang::fg::green << "[" << std::setw(width) << i_line + 1 << '/' << lines.size() << "] " << rang::fg::reset; std::smatch matchex; - int status = -1; if (std::regex_search(line, matchex, mangled_function)) { std::string prefix = matchex.prefix().str(); std::string function = line.substr(matchex.position() + 1, matchex.length() - 2); @@ -43,13 +42,7 @@ operator<<(std::ostream& os, const BacktraceManager& btm) os << prefix << '('; if (function.size() > 0) { - char* demangled = abi::__cxa_demangle(function.c_str(), NULL, NULL, &status); - if (status == 0) { - os << rang::style::bold << demangled << rang::style::reset; - free(demangled); - } else { - os << rang::style::bold << function << rang::style::reset; - } + os << rang::style::bold << demangle(function) << rang::style::reset; } os << '+' << suffix << '\n'; } else { diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 21b313acd63d3396793bb67af7406443fe902344..fe9b5e6fed3ff7ddd796ab0081ce144e8b535b90 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -5,6 +5,7 @@ add_library( BuildInfo.cpp BacktraceManager.cpp ConsoleManager.cpp + Demangle.cpp Exceptions.cpp FPEManager.cpp Messenger.cpp diff --git a/src/utils/Demangle.cpp b/src/utils/Demangle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a38939d26f72fdb68315a9a3917d9a1ac6947f80 --- /dev/null +++ b/src/utils/Demangle.cpp @@ -0,0 +1,19 @@ +#include <utils/Demangle.hpp> + +#include <cxxabi.h> +#include <memory> + +std::string +demangle(const std::string_view mangled) +{ + int status = -1; + + char* cxa_demangled = abi::__cxa_demangle(mangled.data(), NULL, NULL, &status); + if (status == 0) { + std::string demangled{cxa_demangled}; + free(cxa_demangled); + return demangled; + } else { + return std::string{mangled}; + } +} diff --git a/src/utils/Demangle.hpp b/src/utils/Demangle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9b7d25b4eb9405ee0278618fd25767212c0a159 --- /dev/null +++ b/src/utils/Demangle.hpp @@ -0,0 +1,16 @@ +#ifndef DEMANGLE_HPP +#define DEMANGLE_HPP + +#include <string> +#include <typeinfo> + +std::string demangle(const std::string_view mangled); + +template <typename T> +inline std::string +demangle() +{ + return demangle(typeid(T).name()); +} + +#endif // DEMANGLE_HPP diff --git a/src/utils/EscapedString.hpp b/src/utils/EscapedString.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ed525abd0368614fb756fd8c7795bb1c7ea178c6 --- /dev/null +++ b/src/utils/EscapedString.hpp @@ -0,0 +1,128 @@ +#ifndef ESCAPED_STRING_HPP +#define ESCAPED_STRING_HPP + +#include <utils/PugsMacros.hpp> + +#include <sstream> +#include <string> +#include <string_view> + +PUGS_INLINE std::string +unescapeString(std::string_view input_string) +{ + std::stringstream ss; + for (size_t i = 1; i < input_string.size() - 1; ++i) { + char c = input_string[i]; + if (c == '\\') { + ++i; + char next = input_string[i]; + switch (next) { + case '\'': { + ss << '\''; + break; + } + case '"': { + ss << '\"'; + break; + } + case '?': { + ss << '\?'; + break; + } + case '\\': { + ss << '\\'; + break; + } + case 'a': { + ss << '\a'; + break; + } + case 'b': { + ss << '\b'; + break; + } + case 'f': { + ss << '\f'; + break; + } + case 'n': { + ss << '\n'; + break; + } + case 'r': { + ss << '\r'; + break; + } + case 't': { + ss << '\t'; + break; + } + case 'v': { + ss << '\v'; + break; + } + } + } else { + ss << input_string[i]; + } + } + + return ss.str(); +} + +PUGS_INLINE std::string +escapeString(std::string_view input_string) +{ + std::stringstream ss; + for (size_t i = 0; i < input_string.size(); ++i) { + char c = input_string[i]; + switch (c) { + case '\\': { + ss << R"(\\)"; + break; + } + case '\"': { + ss << R"(\")"; + break; + } + case '?': { + ss << R"(\?)"; + break; + } + case '\a': { + ss << R"(\a)"; + break; + } + case '\b': { + ss << R"(\b)"; + break; + } + case '\f': { + ss << R"(\f)"; + break; + } + case '\n': { + ss << R"(\n)"; + break; + } + case '\r': { + ss << R"(\r)"; + break; + } + case '\t': { + ss << R"(\t)"; + break; + } + case '\v': { + ss << R"(\v)"; + break; + } + default: { + ss << c; + } + } + } + return ss.str(); +} + +#endif // ESCAPED_STRING_HPP diff --git a/src/utils/Exceptions.cpp b/src/utils/Exceptions.cpp index 85534848f3454e2337685d8ddb1ac81b7ad5d776..1bf598b7ceac54e0cff3d8b2662b35bdc0654e07 100644 --- a/src/utils/Exceptions.cpp +++ b/src/utils/Exceptions.cpp @@ -10,7 +10,7 @@ RawError::RawError(std::string_view error_msg) : IExitError(std::string{error_ms NormalError::NormalError(std::string_view error_msg) : IExitError([&] { std::ostringstream os; - os << rang::style::bold << "Error:" << rang::style::reset << ' ' << error_msg; + os << rang::style::bold << "error:" << rang::style::reset << ' ' << error_msg; return os.str(); }()) {} @@ -18,7 +18,7 @@ NormalError::NormalError(std::string_view error_msg) UnexpectedError::UnexpectedError(std::string_view error_msg) : IBacktraceError([&] { std::ostringstream os; - os << rang::fgB::red << "Unexpected error:" << rang::style::reset << ' ' << error_msg; + os << rang::fgB::red << "unexpected error:" << rang::style::reset << ' ' << error_msg; return os.str(); }()) {} @@ -26,7 +26,7 @@ UnexpectedError::UnexpectedError(std::string_view error_msg) NotImplementedError::NotImplementedError(std::string_view error_msg) : IBacktraceError([&] { std::ostringstream os; - os << rang::fgB::yellow << "Not implemented yet:" << rang::style::reset << ' ' << error_msg; + os << rang::fgB::yellow << "not implemented yet:" << rang::style::reset << ' ' << error_msg; return os.str(); }()) {} diff --git a/src/utils/Exceptions.hpp b/src/utils/Exceptions.hpp index 2b7906dfee7de16e848633597a7645c146084103..eb229198bc7fcc16d3d4216e859b66c6cf496376 100644 --- a/src/utils/Exceptions.hpp +++ b/src/utils/Exceptions.hpp @@ -1,7 +1,8 @@ -#ifndef EXCEPTIONS_H -#define EXCEPTIONS_H +#ifndef EXCEPTIONS_HPP +#define EXCEPTIONS_HPP #include <stdexcept> +#include <string> struct IExitError : public std::runtime_error { @@ -54,4 +55,4 @@ struct NotImplementedError : IBacktraceError NotImplementedError(std::string_view error_msg); }; -#endif /* EXCEPTIONS_H */ +#endif // EXCEPTIONS_HPP diff --git a/src/utils/Messenger.hpp b/src/utils/Messenger.hpp index 1f8903eccf8465e5d06ebc2164ec8f3768672289..437ea62a0d734274900c8af1b474749813e1aeaa 100644 --- a/src/utils/Messenger.hpp +++ b/src/utils/Messenger.hpp @@ -298,10 +298,11 @@ class Messenger DataType allReduceMin(const DataType& data) const { -#ifdef PUGS_HAS_MPI static_assert(not std::is_const_v<DataType>); static_assert(std::is_arithmetic_v<DataType>); + static_assert(not std::is_same_v<DataType, bool>); +#ifdef PUGS_HAS_MPI MPI_Datatype mpi_datatype = Messenger::helper::mpiType<DataType>(); DataType min_data = data; @@ -315,12 +316,49 @@ class Messenger template <typename DataType> DataType - allReduceMax(const DataType& data) const + allReduceAnd(const DataType& data) const + { + static_assert(std::is_same_v<DataType, bool>); + +#ifdef PUGS_HAS_MPI + MPI_Datatype mpi_datatype = Messenger::helper::mpiType<DataType>(); + + DataType max_data = data; + MPI_Allreduce(&data, &max_data, 1, mpi_datatype, MPI_LAND, MPI_COMM_WORLD); + + return max_data; +#else // PUGS_HAS_MPI + return data; +#endif // PUGS_HAS_MPI + } + + template <typename DataType> + DataType + allReduceOr(const DataType& data) const { + static_assert(std::is_same_v<DataType, bool>); + #ifdef PUGS_HAS_MPI + MPI_Datatype mpi_datatype = Messenger::helper::mpiType<DataType>(); + + DataType max_data = data; + MPI_Allreduce(&data, &max_data, 1, mpi_datatype, MPI_LOR, MPI_COMM_WORLD); + + return max_data; +#else // PUGS_HAS_MPI + return data; +#endif // PUGS_HAS_MPI + } + + template <typename DataType> + DataType + allReduceMax(const DataType& data) const + { static_assert(not std::is_const_v<DataType>); static_assert(std::is_arithmetic_v<DataType>); + static_assert(not std::is_same_v<DataType, bool>); +#ifdef PUGS_HAS_MPI MPI_Datatype mpi_datatype = Messenger::helper::mpiType<DataType>(); DataType max_data = data; @@ -336,8 +374,11 @@ class Messenger DataType allReduceSum(const DataType& data) const { -#ifdef PUGS_HAS_MPI static_assert(not std::is_const_v<DataType>); + static_assert(std::is_arithmetic_v<DataType>); + static_assert(not std::is_same_v<DataType, bool>); + +#ifdef PUGS_HAS_MPI if constexpr (std::is_arithmetic_v<DataType>) { MPI_Datatype mpi_datatype = Messenger::helper::mpiType<DataType>(); @@ -549,6 +590,20 @@ barrier() messenger().barrier(); } +template <typename DataType> +PUGS_INLINE DataType +allReduceAnd(const DataType& data) +{ + return messenger().allReduceAnd(data); +} + +template <typename DataType> +PUGS_INLINE DataType +allReduceOr(const DataType& data) +{ + return messenger().allReduceOr(data); +} + template <typename DataType> PUGS_INLINE DataType allReduceMax(const DataType& data) diff --git a/src/utils/PugsAssert.hpp b/src/utils/PugsAssert.hpp index 15c47de7d1adae3482f3b06d4a0e6a8e55c6861d..def5604de9cd870e0e2abcd67f228b7ce0143f2e 100644 --- a/src/utils/PugsAssert.hpp +++ b/src/utils/PugsAssert.hpp @@ -2,6 +2,7 @@ #define PUGS_ASSERT_HPP #include <utils/PugsMacros.hpp> +#include <utils/PugsTraits.hpp> #include <iostream> #include <rang.hpp> @@ -12,7 +13,7 @@ class AssertError { private: const std::string m_file; - const int m_line; + const size_t m_line; const std::string m_function; const std::string m_test; const std::string m_message; @@ -22,59 +23,95 @@ class AssertError operator<<(std::ostream& os, const AssertError& assert_error) { os << '\n' - << rang::style::bold << "---------- Assertion error -----------\n" + << "---------- Assertion error -----------\n" << " at " << assert_error.m_file << ':' << assert_error.m_line << '\n' << " in " << assert_error.m_function << '\n' - << " assertion (" << rang::fgB::red << assert_error.m_test << rang::fg::reset << ") failed!\n"; + << " assertion (" << assert_error.m_test << ") failed!\n"; if (not assert_error.m_message.empty()) { - os << ' ' << rang::fgB::yellow << assert_error.m_message << rang::fg::reset << '\n'; + os << ' ' << assert_error.m_message << '\n'; } - os << "--------------------------------------" << rang::style::reset << '\n'; + os << "--------------------------------------" << '\n'; return os; } - AssertError(const AssertError&) = default; - AssertError(const std::string& file, - int line, + template <typename... Args> + AssertError(const std::string& filename, + size_t line, const std::string& function, - const std::string& test, - const std::string& message = "") - : m_file(file), m_line(line), m_function(function), m_test(test), m_message(message) + const std::tuple<Args...>& tuple_args, + const std::string_view args_string) + : m_file{filename}, + m_line{line}, + m_function{function}, + m_test{[&] { + if constexpr (sizeof...(Args) == 1) { + return std::string(args_string); + } else { + std::string_view message = std::get<1>(tuple_args); + std::string test_str{args_string, 0, args_string.size() - message.size() - 2}; + while (test_str[test_str.size() - 1] == ' ' or test_str[test_str.size() - 1] == ',') { + test_str.resize(test_str.size() - 1); + } + return test_str; + } + }()}, + m_message{[&] { + if constexpr (sizeof...(Args) == 1) { + return std::string{}; + } else { + return std::get<1>(tuple_args); + } + }()} { ; } - - ~AssertError() = default; }; -PRAGMA_DIAGNOSTIC_IGNORED_WATTRIBUTES -inline bool __attribute__((analyzer_noreturn)) _pugs_assert(bool assert) +template <typename... Args> +struct AssertChecker; + +template <typename... Args> +struct AssertChecker<std::tuple<Args...> > { - return assert; -} -PRAGMA_DIAGNOSTIC_POP + void static check_args_type() + { + constexpr size_t size = sizeof...(Args); + static_assert(size >= 1 and size <= 2, "Assert requires 1 or 2 parameters"); + + using ArgsTuple = std::tuple<Args...>; + + using assertion_t = std::tuple_element_t<0, ArgsTuple>; + static_assert(std::is_integral_v<assertion_t> or std::is_pointer_v<assertion_t> or is_std_ptr_v<assertion_t>); + + if constexpr (size == 2) { + using message_t = std::decay_t<std::remove_const_t<std::tuple_element_t<1, ArgsTuple> > >; + + static_assert(std::is_same_v<message_t, const char*>, "optional second argument must be a string literal"); + } + } +}; #ifdef NDEBUG -// Useless test is there to check syntax even in optimized mode. Costs nothing. -#define Assert(assertion, ...) \ - if (not _pugs_assert(assertion)) { \ - using vargs_t = decltype(std::make_tuple(__VA_ARGS__)); \ - static_assert(std::tuple_size_v<vargs_t> <= 1, "too many arguments"); \ +#define Assert(...) \ + { \ + using TupleArgs = decltype(std::make_tuple(__VA_ARGS__)); \ + AssertChecker<TupleArgs>::check_args_type(); \ } #else // NDEBUG -#define Assert(assertion, ...) \ - if (not _pugs_assert(assertion)) { \ - using vargs_t = decltype(std::make_tuple(__VA_ARGS__)); \ - static_assert(std::tuple_size_v<vargs_t> <= 1, "too many arguments"); \ - if constexpr (std::tuple_size_v<vargs_t> == 0) { \ - throw AssertError(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion); \ - } else { \ - throw AssertError(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion, #__VA_ARGS__); \ - } \ +#define Assert(...) \ + { \ + using TupleArgs = decltype(std::make_tuple(__VA_ARGS__)); \ + AssertChecker<TupleArgs>::check_args_type(); \ + constexpr int tuple_size = std::tuple_size_v<TupleArgs>; \ + static_assert(tuple_size >= 1 and tuple_size <= 2); \ + auto args = std::forward_as_tuple(__VA_ARGS__); \ + if (not static_cast<bool>(std::get<0>(args))) { \ + throw AssertError(__FILE__, __LINE__, __PRETTY_FUNCTION__, args, #__VA_ARGS__); \ + } \ } #endif // NDEBUG diff --git a/src/utils/PugsTraits.hpp b/src/utils/PugsTraits.hpp index a6b6dd3aa39280924cde030b3b5a84f15f88233d..e34e0433bb69316af695fec1c8d571ef23e03155 100644 --- a/src/utils/PugsTraits.hpp +++ b/src/utils/PugsTraits.hpp @@ -2,13 +2,18 @@ #define PUGS_TRAITS_HPP #include <cstddef> +#include <memory> #include <type_traits> +#include <variant> +#include <vector> template <size_t N, typename T> class TinyVector; template <size_t N, typename T> class TinyMatrix; +// Traits is_trivially_castable + template <typename T> inline constexpr bool is_trivially_castable = std::is_trivial_v<T>; @@ -22,7 +27,72 @@ inline constexpr bool is_trivially_castable<TinyMatrix<N, T>> = is_trivially_cas template <size_t N, typename T> inline constexpr bool is_trivially_castable<const TinyMatrix<N, T>> = is_trivially_castable<T>; +// Traits is_false + template <typename T> inline constexpr bool is_false_v = false; +// Traits is_shared_ptr + +template <typename T> +inline constexpr bool is_shared_ptr_v = false; + +template <typename T> +inline constexpr bool is_shared_ptr_v<std::shared_ptr<T>> = true; + +// Traits is_shared_ptr + +template <typename T> +inline constexpr bool is_unique_ptr_v = false; + +template <typename T> +inline constexpr bool is_unique_ptr_v<std::unique_ptr<T>> = true; + +// Traits is_weak_ptr + +template <typename T> +inline constexpr bool is_weak_ptr_v = false; + +template <typename T> +inline constexpr bool is_weak_ptr_v<std::weak_ptr<T>> = true; + +// Traits is_std_ptr + +template <typename T> +inline constexpr bool is_std_ptr_v = false; + +template <typename T> +inline constexpr bool is_std_ptr_v<std::shared_ptr<T>> = true; +template <typename T> +inline constexpr bool is_std_ptr_v<std::unique_ptr<T>> = true; +template <typename T> +inline constexpr bool is_std_ptr_v<std::weak_ptr<T>> = true; + +// Traits is_std_vector + +template <typename T> +inline constexpr bool is_std_vector_v = false; + +template <typename T> +inline constexpr bool is_std_vector_v<std::vector<T>> = true; + +// Traits is_tiny_vector + +template <typename T> +inline constexpr bool is_tiny_vector_v = false; + +template <size_t N, typename T> +inline constexpr bool is_tiny_vector_v<TinyVector<N, T>> = true; + +// Traits is_tiny_vector +// helper to check if a type is part of a variant + +template <typename T, typename V> +struct is_variant; + +template <typename T, typename... ALL_T> +struct is_variant<T, std::variant<ALL_T...>> : public std::disjunction<std::is_same<T, ALL_T>...> +{ +}; + #endif // PUGS_TRAITS_HPP diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp index ec024977f7cd21b7ebaca795f379b0eea6ad06ec..de9e8830fbbc200d724f3f49bf9d44db82e3438b 100644 --- a/src/utils/PugsUtils.cpp +++ b/src/utils/PugsUtils.cpp @@ -48,7 +48,7 @@ initialize(int& argc, char* argv[]) { CLI::App app{"Pugs help"}; - app.add_option("filename,-f,--filename", filename, "gmsh file"); + app.add_option("filename,-f,--filename", filename, "pugs script file")->check(CLI::ExistingFile); int threads = -1; app.add_option("--threads", threads, "Number of Kokkos threads") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 81e18ea778e484d9c7b8d963859b4befa8972571..2dfd3234486b352e5b9f27e13e10001846008bc1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,18 +6,79 @@ include_directories(${PUGS_SOURCE_DIR}/tests) add_executable (unit_tests test_main.cpp + test_AffectationProcessor.cpp + test_AffectationToStringProcessor.cpp test_Array.cpp + test_ArraySubscriptProcessor.cpp test_ArrayUtils.cpp + test_ASTBuilder.cpp + test_ASTDotPrinter.cpp + test_ASTModulesImporter.cpp + test_ASTNode.cpp + test_ASTNodeAffectationExpressionBuilder.cpp + test_ASTNodeArraySubscriptExpressionBuilder.cpp + test_ASTNodeBinaryOperatorExpressionBuilder.cpp + test_ASTNodeBuiltinFunctionExpressionBuilder.cpp + test_ASTNodeDataType.cpp + test_ASTNodeDataTypeBuilder.cpp + test_ASTNodeDataTypeChecker.cpp + test_ASTNodeDataTypeFlattener.cpp + test_ASTNodeDeclarationToAffectationConverter.cpp + test_ASTNodeEmptyBlockCleaner.cpp + test_ASTNodeExpressionBuilder.cpp + test_ASTNodeFunctionEvaluationExpressionBuilder.cpp + test_ASTNodeFunctionExpressionBuilder.cpp + test_ASTNodeIncDecExpressionBuilder.cpp + test_ASTNodeJumpPlacementChecker.cpp + test_ASTNodeListAffectationExpressionBuilder.cpp + test_ASTNodeListProcessor.cpp + test_ASTNodeNaturalConversionChecker.cpp + test_ASTNodeTypeCleaner.cpp + test_ASTNodeUnaryOperatorExpressionBuilder.cpp + test_ASTPrinter.cpp + test_ASTSymbolTableBuilder.cpp + test_ASTSymbolInitializationChecker.cpp + test_BreakProcessor.cpp + test_BinaryExpressionProcessor_arithmetic.cpp + test_BinaryExpressionProcessor_comparison.cpp + test_BinaryExpressionProcessor_equality.cpp + test_BinaryExpressionProcessor_logic.cpp test_BiCGStab.cpp + test_BuiltinFunctionEmbedder.cpp + test_BuiltinFunctionEmbedderTable.cpp + test_BuiltinFunctionProcessor.cpp + test_MathModule.cpp + test_ContinueProcessor.cpp + test_ConcatExpressionProcessor.cpp test_CRSMatrix.cpp + test_DataVariant.cpp + test_DoWhileProcessor.cpp + test_EmbeddedData.cpp + test_ExecutionPolicy.cpp + test_FakeProcessor.cpp + test_ForProcessor.cpp + test_FunctionProcessor.cpp + test_FunctionSymbolId.cpp + test_FunctionTable.cpp + test_IfProcessor.cpp + test_IncDecExpressionProcessor.cpp + test_INodeProcessor.cpp test_ItemType.cpp + test_ListAffectationProcessor.cpp + test_NameProcessor.cpp + test_OStreamProcessor.cpp test_PCG.cpp + test_PugsFunctionAdapter.cpp test_PugsAssert.cpp test_RevisionInfo.cpp test_SparseMatrixDescriptor.cpp + test_SymbolTable.cpp test_TinyMatrix.cpp test_TinyVector.cpp + test_TupleToVectorProcessor.cpp + test_UnaryExpressionProcessor.cpp test_Vector.cpp + test_WhileProcessor.cpp ) add_executable (mpi_unit_tests @@ -26,6 +87,11 @@ add_executable (mpi_unit_tests ) target_link_libraries (unit_tests + PugsLanguage + PugsLanguageAST + PugsLanguageModules + PugsLanguageUtils + PugsMesh PugsUtils kokkos ${PARMETIS_LIBRARIES} @@ -35,6 +101,7 @@ target_link_libraries (unit_tests target_link_libraries (mpi_unit_tests PugsUtils + PugsMesh kokkos ${PARMETIS_LIBRARIES} ${MPI_CXX_LINK_FLAGS} ${MPI_CXX_LIBRARIES} diff --git a/tests/mpi_test_Messenger.cpp b/tests/mpi_test_Messenger.cpp index beea7430bc83b17b11dc6ab2375f70d5a13e785a..19d89851c82020c0f10e4eaeac919595059e8fab 100644 --- a/tests/mpi_test_Messenger.cpp +++ b/tests/mpi_test_Messenger.cpp @@ -130,6 +130,18 @@ TEST_CASE("Messenger", "[mpi]") const int max_value = parallel::allReduceMax(parallel::rank() + 3); REQUIRE(max_value == static_cast<int>((parallel::size() - 1) + 3)); + + const bool and_value = parallel::allReduceAnd(true); + REQUIRE(and_value == true); + + const bool and_value_2 = parallel::allReduceAnd(parallel::rank() > 0); + REQUIRE(and_value_2 == false); + + const bool or_value = parallel::allReduceOr(false); + REQUIRE(or_value == false); + + const bool or_value_2 = parallel::allReduceOr(parallel::rank() > 0); + REQUIRE(or_value_2 == (parallel::size() > 1)); } SECTION("all to all") diff --git a/tests/mpi_test_main.cpp b/tests/mpi_test_main.cpp index 3b40c79cf4f37a8424f7c7d4ad9fefd1171fbdc0..565e46690910c05d6800ca1931bd811db790cc12 100644 --- a/tests/mpi_test_main.cpp +++ b/tests/mpi_test_main.cpp @@ -13,6 +13,9 @@ main(int argc, char* argv[]) parallel::Messenger::create(argc, argv); Kokkos::initialize({4, -1, -1, true}); + // Disable outputs from tested classes to the standard output + std::cout.setstate(std::ios::badbit); + if (parallel::rank() != 0) { setenv("GCOV_PREFIX", "/dev/null", 1); } diff --git a/tests/test_ASTBuilder.cpp b/tests/test_ASTBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2399a78617d6a6f30774fbc70be735d5850967d3 --- /dev/null +++ b/tests/test_ASTBuilder.cpp @@ -0,0 +1,641 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::none}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTBuilder", "[language]") +{ + rang::setControlMode(rang::control::Off); + SECTION("AST parsing") + { + SECTION("declarations with init") + { + std::string_view data = R"( +let n:N, n = 2; +let z:Z, z = 3; +let r :R,r= 2.3e-5; +let b: B ,b = false; +let s : string, s = "foo"; +)"; + + std::string_view result = R"( +(root) + +-(language::var_declaration) + | +-(language::name:n) + | +-(language::N_set) + | +-(language::name:n) + | `-(language::integer:2) + +-(language::var_declaration) + | +-(language::name:z) + | +-(language::Z_set) + | +-(language::name:z) + | `-(language::integer:3) + +-(language::var_declaration) + | +-(language::name:r) + | +-(language::R_set) + | +-(language::name:r) + | `-(language::real:2.3e-5) + +-(language::var_declaration) + | +-(language::name:b) + | +-(language::B_set) + | +-(language::name:b) + | `-(language::false_kw) + `-(language::var_declaration) + +-(language::name:s) + +-(language::string_type) + +-(language::name:s) + `-(language::literal:"foo") +)"; + CHECK_AST(data, result); + } + + SECTION("affectations") + { + std::string_view data = R"( +let n:N; n = 2; +let z:Z; z = 3; +let r:R; r = 2.3e-5; +let b:B; b = false; +let s:string; s = "foo"; +)"; + + std::string_view result = R"( +(root) + +-(language::var_declaration) + | +-(language::name:n) + | `-(language::N_set) + +-(language::eq_op) + | +-(language::name:n) + | `-(language::integer:2) + +-(language::var_declaration) + | +-(language::name:z) + | `-(language::Z_set) + +-(language::eq_op) + | +-(language::name:z) + | `-(language::integer:3) + +-(language::var_declaration) + | +-(language::name:r) + | `-(language::R_set) + +-(language::eq_op) + | +-(language::name:r) + | `-(language::real:2.3e-5) + +-(language::var_declaration) + | +-(language::name:b) + | `-(language::B_set) + +-(language::eq_op) + | +-(language::name:b) + | `-(language::false_kw) + +-(language::var_declaration) + | +-(language::name:s) + | `-(language::string_type) + `-(language::eq_op) + +-(language::name:s) + `-(language::literal:"foo") +)"; + CHECK_AST(data, result); + } + + SECTION("empty blocks simplification") + { + std::string_view data = R"( +{ + /* nothing but a block */ + { + ; // nothing + } +} +)"; + + std::string_view result = R"( +(root) +)"; + CHECK_AST(data, result); + } + + SECTION("operators precedence") + { + SECTION("basic operations") + { + std::string_view data = R"( +2+3.2*6 - 3.2/4; +)"; + + std::string_view result = R"( +(root) + `-(language::minus_op) + +-(language::plus_op) + | +-(language::integer:2) + | `-(language::multiply_op) + | +-(language::real:3.2) + | `-(language::integer:6) + `-(language::divide_op) + +-(language::real:3.2) + `-(language::integer:4) +)"; + CHECK_AST(data, result); + } + + SECTION("parented expression") + { + std::string_view data = R"( +(2+3)*6; +)"; + + std::string_view result = R"( +(root) + `-(language::multiply_op) + +-(language::plus_op) + | +-(language::integer:2) + | `-(language::integer:3) + `-(language::integer:6) +)"; + CHECK_AST(data, result); + } + + SECTION("all operators mix") + { + std::string_view data = R"( +1+2 and 3<= 2 * 4 - 1 == 2 or 2>=1 / 5 xor 7 and 2 or 2 <3 >7 xor -2 + true - not false; +)"; + + std::string_view result = R"( +(root) + `-(language::or_op) + +-(language::or_op) + | +-(language::and_op) + | | +-(language::plus_op) + | | | +-(language::integer:1) + | | | `-(language::integer:2) + | | `-(language::eqeq_op) + | | +-(language::lesser_or_eq_op) + | | | +-(language::integer:3) + | | | `-(language::minus_op) + | | | +-(language::multiply_op) + | | | | +-(language::integer:2) + | | | | `-(language::integer:4) + | | | `-(language::integer:1) + | | `-(language::integer:2) + | `-(language::and_op) + | +-(language::xor_op) + | | +-(language::greater_or_eq_op) + | | | +-(language::integer:2) + | | | `-(language::divide_op) + | | | +-(language::integer:1) + | | | `-(language::integer:5) + | | `-(language::integer:7) + | `-(language::integer:2) + `-(language::xor_op) + +-(language::greater_op) + | +-(language::lesser_op) + | | +-(language::integer:2) + | | `-(language::integer:3) + | `-(language::integer:7) + `-(language::minus_op) + +-(language::plus_op) + | +-(language::unary_minus) + | | `-(language::integer:2) + | `-(language::true_kw) + `-(language::unary_not) + `-(language::false_kw) +)"; + CHECK_AST(data, result); + } + } + + SECTION("unary operator simplification") + { + SECTION("multiple not") + { + std::string_view data = R"( +not not not not true; +not not not false; +)"; + + std::string_view result = R"( +(root) + +-(language::true_kw) + `-(language::unary_not) + `-(language::false_kw) +)"; + CHECK_AST(data, result); + } + + SECTION("multiple unary plus") + { + std::string_view data = R"( ++ + + 3; +)"; + + std::string_view result = R"( +(root) + `-(language::integer:3) +)"; + CHECK_AST(data, result); + } + + SECTION("multiple unary minus") + { + std::string_view data = R"( +- - + - - 3; +- + - - 2; +)"; + + std::string_view result = R"( +(root) + +-(language::integer:3) + `-(language::unary_minus) + `-(language::integer:2) +)"; + CHECK_AST(data, result); + } + + SECTION("sums and unary plus/minus") + { + std::string_view data = R"( +1 - - 3; +1 + - 2; +4 - + 3; +)"; + + std::string_view result = R"( +(root) + +-(language::plus_op) + | +-(language::integer:1) + | `-(language::integer:3) + +-(language::minus_op) + | +-(language::integer:1) + | `-(language::integer:2) + `-(language::minus_op) + +-(language::integer:4) + `-(language::integer:3) +)"; + CHECK_AST(data, result); + } + } + + SECTION("subscript handling") + { + std::string_view data = R"( +u[a]; +u[f(c)]; +u[u[b]]; +)"; + + std::string_view result = R"( +(root) + +-(language::subscript_expression) + | +-(language::name:u) + | `-(language::name:a) + +-(language::subscript_expression) + | +-(language::name:u) + | `-(language::function_evaluation) + | +-(language::name:f) + | `-(language::name:c) + `-(language::subscript_expression) + +-(language::name:u) + `-(language::subscript_expression) + +-(language::name:u) + `-(language::name:b) +)"; + CHECK_AST(data, result); + } + + SECTION("post incr/decr rearrangements") + { + std::string_view data = R"( +1++; +2--; +)"; + + std::string_view result = R"( +(root) + +-(language::post_plusplus) + | `-(language::integer:1) + `-(language::post_minusminus) + `-(language::integer:2) +)"; + CHECK_AST(data, result); + } + + SECTION("statement block simplification (one instruction per block)") + { + std::string_view data = R"( +if (a > 0) { + a = 0; +} else { + a =-1; +} +)"; + + std::string_view result = R"( +(root) + `-(language::if_statement) + +-(language::greater_op) + | +-(language::name:a) + | `-(language::integer:0) + +-(language::eq_op) + | +-(language::name:a) + | `-(language::integer:0) + `-(language::eq_op) + +-(language::name:a) + `-(language::unary_minus) + `-(language::integer:1) +)"; + CHECK_AST(data, result); + } + + SECTION("statement block simplification (one instruction in first block)") + { + std::string_view data = R"( +if (a > 0) { + a = 0; +} else { + a = 3; + a = a++; +} +)"; + + std::string_view result = R"( +(root) + `-(language::if_statement) + +-(language::greater_op) + | +-(language::name:a) + | `-(language::integer:0) + +-(language::eq_op) + | +-(language::name:a) + | `-(language::integer:0) + `-(language::block) + +-(language::eq_op) + | +-(language::name:a) + | `-(language::integer:3) + `-(language::eq_op) + +-(language::name:a) + `-(language::post_plusplus) + `-(language::name:a) +)"; + CHECK_AST(data, result); + } + + SECTION("statement block simplification (one instruction in second block)") + { + std::string_view data = R"( +if (a > 0) { + a = 0; + a++; +} else { + a = 3; +} +)"; + + std::string_view result = R"( +(root) + `-(language::if_statement) + +-(language::greater_op) + | +-(language::name:a) + | `-(language::integer:0) + +-(language::block) + | +-(language::eq_op) + | | +-(language::name:a) + | | `-(language::integer:0) + | `-(language::post_plusplus) + | `-(language::name:a) + `-(language::eq_op) + +-(language::name:a) + `-(language::integer:3) +)"; + CHECK_AST(data, result); + } + + SECTION("statement block non-simplification (one declaration in each block)") + { + std::string_view data = R"( +if (a > 0) { + let b:R, b = a; +} else { + let c:R, c = 2*a; +} +)"; + + std::string_view result = R"( +(root) + `-(language::if_statement) + +-(language::greater_op) + | +-(language::name:a) + | `-(language::integer:0) + +-(language::block) + | `-(language::var_declaration) + | +-(language::name:b) + | +-(language::R_set) + | +-(language::name:b) + | `-(language::name:a) + `-(language::block) + `-(language::var_declaration) + +-(language::name:c) + +-(language::R_set) + +-(language::name:c) + `-(language::multiply_op) + +-(language::integer:2) + `-(language::name:a) +)"; + CHECK_AST(data, result); + } + + SECTION("statement block simplification (one declaration in first block)") + { + std::string_view data = R"( +if (a > 0) { + let b:R, b = a; +} else { + let c:R, c = 2*a; + ++a; +} +)"; + + std::string_view result = R"( +(root) + `-(language::if_statement) + +-(language::greater_op) + | +-(language::name:a) + | `-(language::integer:0) + +-(language::block) + | `-(language::var_declaration) + | +-(language::name:b) + | +-(language::R_set) + | +-(language::name:b) + | `-(language::name:a) + `-(language::block) + +-(language::var_declaration) + | +-(language::name:c) + | +-(language::R_set) + | +-(language::name:c) + | `-(language::multiply_op) + | +-(language::integer:2) + | `-(language::name:a) + `-(language::unary_plusplus) + `-(language::name:a) +)"; + CHECK_AST(data, result); + } + + SECTION("statement block simplification (one declaration in second block)") + { + std::string_view data = R"( +if (a > 0) { + let b:R, b = a; + ++b; +} else { + let c:R, c = 2*a; +} +)"; + + std::string_view result = R"( +(root) + `-(language::if_statement) + +-(language::greater_op) + | +-(language::name:a) + | `-(language::integer:0) + +-(language::block) + | +-(language::var_declaration) + | | +-(language::name:b) + | | +-(language::R_set) + | | +-(language::name:b) + | | `-(language::name:a) + | `-(language::unary_plusplus) + | `-(language::name:b) + `-(language::block) + `-(language::var_declaration) + +-(language::name:c) + +-(language::R_set) + +-(language::name:c) + `-(language::multiply_op) + +-(language::integer:2) + `-(language::name:a) +)"; + CHECK_AST(data, result); + } + + SECTION("for-statements simplification") + { + std::string_view data = R"( +for(let i:N, i=0; i<10; ++i) { + i += 3; +} +)"; + + std::string_view result = R"( +(root) + `-(language::for_statement) + +-(language::var_declaration) + | +-(language::name:i) + | +-(language::N_set) + | +-(language::name:i) + | `-(language::integer:0) + +-(language::lesser_op) + | +-(language::name:i) + | `-(language::integer:10) + +-(language::unary_plusplus) + | `-(language::name:i) + `-(language::pluseq_op) + +-(language::name:i) + `-(language::integer:3) +)"; + CHECK_AST(data, result); + } + + SECTION("for-statements simplification (complex block)") + { + std::string_view data = R"( +for(let i:N, i=0; i<10; ++i) { + i += 3; + let j:R, j=i/5.; +} +)"; + + std::string_view result = R"( +(root) + `-(language::for_statement) + +-(language::var_declaration) + | +-(language::name:i) + | +-(language::N_set) + | +-(language::name:i) + | `-(language::integer:0) + +-(language::lesser_op) + | +-(language::name:i) + | `-(language::integer:10) + +-(language::unary_plusplus) + | `-(language::name:i) + `-(language::for_statement_block) + +-(language::pluseq_op) + | +-(language::name:i) + | `-(language::integer:3) + `-(language::var_declaration) + +-(language::name:j) + +-(language::R_set) + +-(language::name:j) + `-(language::divide_op) + +-(language::name:i) + `-(language::real:5.) +)"; + CHECK_AST(data, result); + } + + SECTION("ostream simplifications") + { + std::string_view data = R"( +cout << 1+2 << "\n"; +cerr << "error?\n"; +clog << "log " << l << "\n"; +)"; + + std::string_view result = R"( +(root) + +-(language::cout_kw) + | +-(language::plus_op) + | | +-(language::integer:1) + | | `-(language::integer:2) + | `-(language::literal:"\n") + +-(language::cerr_kw) + | `-(language::literal:"error?\n") + `-(language::clog_kw) + +-(language::literal:"log ") + +-(language::name:l) + `-(language::literal:"\n") +)"; + CHECK_AST(data, result); + } + } + + SECTION("errors") + { + SECTION("syntax error") + { + std::string_view data = R"( +1+; // syntax error +)"; + + string_input input{data, "test.pgs"}; + + REQUIRE_THROWS_WITH(ASTBuilder::build(input), "parse error, missing expression"); + } + } +} diff --git a/tests/test_ASTDotPrinter.cpp b/tests/test_ASTDotPrinter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9597ebca0a7d4e448563ea50e109474e6dd7e80 --- /dev/null +++ b/tests/test_ASTDotPrinter.cpp @@ -0,0 +1,51 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/utils/ASTDotPrinter.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_DOT(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTDotPrinter{*ast}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTDotPrinter", "[language]") +{ + rang::setControlMode(rang::control::Off); + + std::string_view data = R"( +let n:N, n = 2 + 3; +)"; + + std::string_view result = R"( +digraph parse_tree +{ + x0 [ label="root \nundefined" ] + x0 -> { x1 } + x1 [ label="language::var_declaration\nlet n:N, n = 2 + 3\nundefined" ] + x1 -> { x2, x3, x4, x5 } + x2 [ label="language::name\nn\nundefined" ] + x3 [ label="language::N_set\nN\nundefined" ] + x4 [ label="language::name\nn\nundefined" ] + x5 [ label="language::plus_op\nundefined" ] + x5 -> { x6, x7 } + x6 [ label="language::integer\n2\nundefined" ] + x7 [ label="language::integer\n3\nundefined" ] +} +)"; + CHECK_DOT(data, result); +} diff --git a/tests/test_ASTModulesImporter.cpp b/tests/test_ASTModulesImporter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ac28918aec2110eefe734b67bf73da2a55ea952 --- /dev/null +++ b/tests/test_ASTModulesImporter.cpp @@ -0,0 +1,104 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <language/utils/SymbolTable.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::data_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTModulesImporter", "[language]") +{ + SECTION("no module") + { + std::string_view data = R"( +)"; + + std::string_view result = R"( +(root:undefined) +)"; + + CHECK_AST(data, result); + } + + SECTION("module instruction removal") + { + std::string_view data = R"( +import math; +)"; + + std::string_view result = R"( +(root:undefined) +)"; + + CHECK_AST(data, result); + } + + SECTION("module multiple import") + { + std::string_view data = R"( +import math; +import math; +)"; + + std::string_view result = R"( +(root:undefined) +)"; + + CHECK_AST(data, result); + } + + SECTION("error") + { + SECTION("unknown module") + { + std::string_view data = R"( +import unknown_module; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + REQUIRE_THROWS_AS(ASTModulesImporter{*ast}, parse_error); + } + + SECTION("symbol already defined") + { + std::string_view data = R"( +import math; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ast->m_symbol_table->add("sin", ast->begin()); + + REQUIRE_THROWS_AS(ASTModulesImporter{*ast}, parse_error); + } + } +} diff --git a/tests/test_ASTNode.cpp b/tests/test_ASTNode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..173c83f8634ef01d8f5b74c526c165f0b2796f48 --- /dev/null +++ b/tests/test_ASTNode.cpp @@ -0,0 +1,87 @@ +#include <catch2/catch.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/node_processor/FakeProcessor.hpp> +#include <utils/Demangle.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNode", "[language]") +{ + rang::setControlMode(rang::control::Off); + SECTION("execute") + { + ASTNode ast_node; + ExecutionPolicy exec_policy; + +#ifndef NDEBUG + REQUIRE_THROWS(ast_node.execute(exec_policy)); +#endif // NDEBUG + + ast_node.m_node_processor = std::make_unique<FakeProcessor>(); + + REQUIRE_NOTHROW(ast_node.execute(exec_policy)); + } + + SECTION("name") + { + ASTNode ast_node; + + ast_node.set_type<language::name>(); + + REQUIRE(ast_node.name() == demangle<language::name>()); + } + + SECTION("string / string_view") + { + SECTION("no content") + { + ASTNode ast_node; + + REQUIRE(ast_node.string() == "<optimized out>"); + REQUIRE(ast_node.string_view() == "<optimized out>"); + } + + SECTION("has content") + { + ASTNode ast_node; + ast_node.source = "content"; + auto& source = ast_node.source; + ast_node.m_begin = TAO_PEGTL_NAMESPACE::internal::iterator{&source[0]}; + ast_node.m_end = TAO_PEGTL_NAMESPACE::internal::iterator{&source[source.size()]}; + + REQUIRE(ast_node.string() == "content"); + REQUIRE(ast_node.string_view() == "content"); + } + + SECTION("children have content") + { + ASTNode ast_node; + ast_node.source = "content"; + auto& source = ast_node.source; + ast_node.m_begin = TAO_PEGTL_NAMESPACE::internal::iterator{&source[2]}; + + { + std::unique_ptr<ASTNode> child0_node = std::make_unique<ASTNode>(); + + child0_node->m_begin = TAO_PEGTL_NAMESPACE::internal::iterator{&source[0]}; + child0_node->m_end = TAO_PEGTL_NAMESPACE::internal::iterator{&source[3]}; + + ast_node.children.emplace_back(std::move(child0_node)); + } + + { + std::unique_ptr<ASTNode> child1_node = std::make_unique<ASTNode>(); + + child1_node->m_begin = TAO_PEGTL_NAMESPACE::internal::iterator{&source[4]}; + child1_node->m_end = TAO_PEGTL_NAMESPACE::internal::iterator{&source[source.size()]}; + + ast_node.children.emplace_back(std::move(child1_node)); + } + + REQUIRE(ast_node.string() == "content"); + REQUIRE(ast_node.string_view() == "content"); + } + } +} diff --git a/tests/test_ASTNodeAffectationExpressionBuilder.cpp b/tests/test_ASTNodeAffectationExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..895fa860eafe2f6216066d422597e539c1a1cd65 --- /dev/null +++ b/tests/test_ASTNodeAffectationExpressionBuilder.cpp @@ -0,0 +1,1858 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolInitializationChecker.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <language/utils/TypeDescriptor.hpp> +#include <utils/Demangle.hpp> +#include <utils/Exceptions.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t, + "builtin_t"}; +const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>; + +#define CHECK_AST_WITH_BUILTIN(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + SymbolTable& symbol_table = *ast->m_symbol_table; \ + auto [i_symbol, success] = symbol_table.add(builtin_data_type.nameOfTypeId(), ast->begin()); \ + if (not success) { \ + throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing"); \ + } \ + \ + i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t); \ + i_symbol->attributes().setIsInitialized(); \ + i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size(); \ + symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); \ + \ + auto [i_symbol_a, success_a] = symbol_table.add("a", ast->begin()); \ + if (not success_a) { \ + throw UnexpectedError("cannot add 'a' of type builtin_t for testing"); \ + } \ + i_symbol_a->attributes().setDataType(ast_node_data_type_from<std::shared_ptr<const double>>); \ + i_symbol_a->attributes().setIsInitialized(); \ + auto [i_symbol_b, success_b] = symbol_table.add("b", ast->begin()); \ + if (not success_b) { \ + throw UnexpectedError("cannot add 'b' of type builtin_t for testing"); \ + } \ + i_symbol_b->attributes().setDataType(ast_node_data_type_from<std::shared_ptr<const double>>); \ + i_symbol_b->attributes().setIsInitialized(); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define CHECK_AST_THROWS_WITH(data, expected_error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_error); \ + } + +#define CHECK_AST_WITH_BUILTIN_THROWS_WITH(data, expected_error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + SymbolTable& symbol_table = *ast->m_symbol_table; \ + auto [i_symbol, success] = symbol_table.add(builtin_data_type.nameOfTypeId(), ast->begin()); \ + if (not success) { \ + throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing"); \ + } \ + \ + i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t); \ + i_symbol->attributes().setIsInitialized(); \ + i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size(); \ + symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); \ + \ + auto [i_symbol_a, success_a] = symbol_table.add("a", ast->begin()); \ + if (not success_a) { \ + throw UnexpectedError("cannot add 'a' of type builtin_t for testing"); \ + } \ + i_symbol_a->attributes().setDataType(ast_node_data_type_from<std::shared_ptr<const double>>); \ + i_symbol_a->attributes().setIsInitialized(); \ + auto [i_symbol_b, success_b] = symbol_table.add("b", ast->begin()); \ + if (not success_b) { \ + throw UnexpectedError("cannot add 'b' of type builtin_t for testing"); \ + } \ + i_symbol_b->attributes().setDataType(ast_node_data_type_from<std::shared_ptr<const double>>); \ + i_symbol_b->attributes().setIsInitialized(); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_error); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeAffectationExpressionBuilder", "[language]") +{ + const std::string demangled_stdstring = demangle(typeid(std::string{}).name()); + + SECTION("Affectations") + { + SECTION("boolean affectation") + { + SECTION("B <- B") + { + std::string_view data = R"( +let b:B, b=true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, bool, bool>) + +-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("unsigned integer affectation") + { + SECTION("N <- B") + { + std::string_view data = R"( +let n:N, n=true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, bool>) + +-(language::name:n:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N <- N") + { + std::string_view data = R"( +let m : N; let n:N, n=m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N <- Z") + { + std::string_view data = R"( +let z:Z; let n :N, n=z; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + +-(language::name:n:NameProcessor) + `-(language::name:z:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("integer affectation") + { + SECTION("Z <- B") + { + std::string_view data = R"( +let z : Z, z=true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, long, bool>) + +-(language::name:z:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z <- N") + { + std::string_view data = R"( +let m : N; let z : Z, z=m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, long, unsigned long>) + +-(language::name:z:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z <- Z") + { + std::string_view data = R"( +let q : Z; let z : Z, z=q; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + +-(language::name:z:NameProcessor) + `-(language::name:q:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("double affectation") + { + SECTION("R <- B") + { + std::string_view data = R"( +let r : R, r=true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, double, bool>) + +-(language::name:r:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R <- N") + { + std::string_view data = R"( +let m : N; let r : R, r=m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, double, unsigned long>) + +-(language::name:r:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R <- Z") + { + std::string_view data = R"( +let z : Z; let r : R, r=z; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + +-(language::name:r:NameProcessor) + `-(language::name:z:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R <- R") + { + std::string_view data = R"( +let s : R; let r : R, r=s; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, double, double>) + +-(language::name:r:NameProcessor) + `-(language::name:s:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R^d affectation") + { + SECTION("R^1 <- R^1") + { + std::string_view data = R"( +let x : R^1; +let y : R^1, y = x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, TinyVector<1ul, double> >) + +-(language::name:y:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 <- R") + { + std::string_view data = R"( +let x : R^1, x = 1.3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, double>) + +-(language::name:x:NameProcessor) + `-(language::real:1.3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 <- Z") + { + std::string_view data = R"( +let x : R^1, x = -1; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + +-(language::name:x:NameProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 <- N") + { + std::string_view data = R"( +let n : N; +let x : R^1, x = n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, unsigned long>) + +-(language::name:x:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 <- B") + { + std::string_view data = R"( +let b : B; +let x : R^1, x = b; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, bool>) + +-(language::name:x:NameProcessor) + `-(language::name:b:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 <- 0") + { + std::string_view data = R"( +let x : R^1, x = 0; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationFromZeroProcessor<TinyVector<1ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 <- R^2") + { + std::string_view data = R"( +let x : R^2; +let y : R^2, y = x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<2ul, double>, TinyVector<2ul, double> >) + +-(language::name:y:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 <- (.,.)") + { + std::string_view data = R"( +let y : R^2, y = (0,1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + +-(language::name:y:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:0:ValueProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 <- 0") + { + std::string_view data = R"( +let x : R^2, x = 0; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationFromZeroProcessor<TinyVector<2ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 <- R^3") + { + std::string_view data = R"( +let x : R^3; +let y : R^3, y = x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<3ul, double>, TinyVector<3ul, double> >) + +-(language::name:y:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 <- 0") + { + std::string_view data = R"( +let x : R^3, x = 0; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationFromZeroProcessor<TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 <- (.,.)") + { + std::string_view data = R"( +let y : R^3, y = (1,2,3); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + +-(language::name:y:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("string affectation") + { + SECTION("string <- B") + { + std::string_view data = R"( +let s : string, s=true; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, )" + + demangled_stdstring + R"(, bool>) + +-(language::name:s:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string <- N") + { + std::string_view data = R"( +let n : N; let s : string, s=n; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, )" + + demangled_stdstring + R"(, unsigned long>) + +-(language::name:s:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string <- Z") + { + std::string_view data = R"( +let z : Z; let s : string, s=z; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, )" + + demangled_stdstring + + R"(, long>) + +-(language::name:s:NameProcessor) + `-(language::name:z:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string <- R") + { + std::string_view data = R"( +let r : R; let s : string, s=r; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, )" + + demangled_stdstring + + R"(, double>) + +-(language::name:s:NameProcessor) + `-(language::name:r:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string <- string") + { + std::string_view data = R"( +let s : string, s="foo"; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, )" + + demangled_stdstring + ", " + demangled_stdstring + R"( >) + +-(language::name:s:NameProcessor) + `-(language::literal:"foo":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("type_id affectation") + { + SECTION("type_id <- type_id") + { + std::string_view data = R"( +let t : builtin_t, t=a; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, EmbeddedData, EmbeddedData>) + +-(language::name:t:NameProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST_WITH_BUILTIN(data, result); + } + } + + SECTION("tuples") + { + SECTION("B tuples") + { + std::string_view data = R"( +let t : (B), t = (true, false); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, bool>) + +-(language::name:t:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::true_kw:ValueProcessor) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N tuples") + { + std::string_view data = R"( +let t : (N), t = (1, 2, 3, 5); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, unsigned long>) + +-(language::name:t:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + +-(language::integer:3:ValueProcessor) + `-(language::integer:5:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z tuples") + { + std::string_view data = R"( +let n : N, n = 3; +let t : (Z), t = (2, n, true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, long>) + +-(language::name:t:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:2:ValueProcessor) + +-(language::name:n:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R tuples") + { + std::string_view data = R"( +let t : (R), t = (2, 3.1, 5); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, double>) + +-(language::name:t:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:2:ValueProcessor) + +-(language::real:3.1:ValueProcessor) + `-(language::integer:5:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^d tuples") + { + std::string_view data = R"( +let a : R^2, a = (2,3.1); +let t1 : (R^2), t1 = (a, (1,2), 0); +let t2 : (R^3), t2 = (0, 0); +let t3 : (R^1), t3 = (1, 2.3, 0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:a:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::real:3.1:ValueProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:t1:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::name:a:NameProcessor) + | +-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + | | +-(language::integer:1:ValueProcessor) + | | `-(language::integer:2:ValueProcessor) + | `-(language::integer:0:ValueProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:t2:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:0:ValueProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, TinyVector<1ul, double> >) + +-(language::name:t3:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::real:2.3:ValueProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string tuples") + { + std::string_view data = R"( +let t : (string), t = ("foo", "bar"); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, )" + + demangled_stdstring + R"( >) + +-(language::name:t:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("type_id tuples") + { + std::string_view data = R"( +let t : (builtin_t), t= (a,b,a); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleFromListProcessor<language::eq_op, EmbeddedData>) + +-(language::name:t:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::name:a:NameProcessor) + +-(language::name:b:NameProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST_WITH_BUILTIN(data, result); + } + } + + SECTION("tuples from singleton") + { + SECTION("B tuples") + { + std::string_view data = R"( +let t : (B), t = true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleProcessor<language::eq_op, bool>) + +-(language::name:t:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N tuples") + { + std::string_view data = R"( +let t : (N), t = 1; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleProcessor<language::eq_op, unsigned long>) + +-(language::name:t:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z tuples") + { + std::string_view data = R"( +let n : N, n = 3; +let t : (Z), t = n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::eq_op:AffectationToTupleProcessor<language::eq_op, long>) + +-(language::name:t:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R tuples") + { + std::string_view data = R"( +let t : (R), t = 3.1; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleProcessor<language::eq_op, double>) + +-(language::name:t:NameProcessor) + `-(language::real:3.1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^d tuples") + { + std::string_view data = R"( +let a : R^2, a = (2,3.1); +let t1 : (R^2), t1 = a; +let t2 : (R^3), t2 = 0; +let t3 : (R^1), t3 = 2.3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:a:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::real:3.1:ValueProcessor) + +-(language::eq_op:AffectationToTupleProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:t1:NameProcessor) + | `-(language::name:a:NameProcessor) + +-(language::eq_op:AffectationToTupleProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:t2:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::eq_op:AffectationToTupleProcessor<language::eq_op, TinyVector<1ul, double> >) + +-(language::name:t3:NameProcessor) + `-(language::real:2.3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string tuples") + { + std::string_view data = R"( +let t : (string), t = "foo"; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleProcessor<language::eq_op, )" + + demangled_stdstring + R"( >) + +-(language::name:t:NameProcessor) + `-(language::literal:"foo":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("type_id tuples") + { + std::string_view data = R"( +let t : (builtin_t), t = a; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationToTupleProcessor<language::eq_op, EmbeddedData>) + +-(language::name:t:NameProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST_WITH_BUILTIN(data, result); + } + } + } + + SECTION("+=") + { + SECTION("N += N") + { + std::string_view data = R"( +let n : N, n=1; n+=n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::pluseq_op:AffectationProcessor<language::pluseq_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R += N") + { + std::string_view data = R"( +let x : R, x=1; x+=2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::pluseq_op:AffectationProcessor<language::pluseq_op, double, long>) + +-(language::name:x:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string += N") + { + std::string_view data = R"( +let s : string, s="foo"; s+=2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, )" + + demangled_stdstring + ", " + demangled_stdstring + R"( >) + | +-(language::name:s:NameProcessor) + | `-(language::literal:"foo":ValueProcessor) + `-(language::pluseq_op:AffectationProcessor<language::pluseq_op, )" + + demangled_stdstring + + R"(, long>) + +-(language::name:s:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 += R^1") + { + std::string_view data = R"( +let x : R^1; +let y : R^1; +x += y; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::pluseq_op:AffectationProcessor<language::pluseq_op, TinyVector<1ul, double>, TinyVector<1ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 += R^2") + { + std::string_view data = R"( +let x : R^2; +let y : R^2; +x += y; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::pluseq_op:AffectationProcessor<language::pluseq_op, TinyVector<2ul, double>, TinyVector<2ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 += R^3") + { + std::string_view data = R"( +let x : R^3; +let y : R^3; +x += y; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::pluseq_op:AffectationProcessor<language::pluseq_op, TinyVector<3ul, double>, TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("-=") + { + SECTION("Z -= Z") + { + std::string_view data = R"( +let z : Z, z=1; z-=2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:z:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::minuseq_op:AffectationProcessor<language::minuseq_op, long, long>) + +-(language::name:z:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R -= R") + { + std::string_view data = R"( +let x : R, x=1; x-=2.3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::minuseq_op:AffectationProcessor<language::minuseq_op, double, double>) + +-(language::name:x:NameProcessor) + `-(language::real:2.3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 -= R^1") + { + std::string_view data = R"( +let x : R^1; +let y : R^1; +x -= y; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::minuseq_op:AffectationProcessor<language::minuseq_op, TinyVector<1ul, double>, TinyVector<1ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 -= R^2") + { + std::string_view data = R"( +let x : R^2; +let y : R^2; +x -= y; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::minuseq_op:AffectationProcessor<language::minuseq_op, TinyVector<2ul, double>, TinyVector<2ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 -= R^3") + { + std::string_view data = R"( +let x : R^3; +let y : R^3; +x -= y; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::minuseq_op:AffectationProcessor<language::minuseq_op, TinyVector<3ul, double>, TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("*=") + { + SECTION("Z *= Z") + { + std::string_view data = R"( +let z : Z, z=1; z*=2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:z:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, long, long>) + +-(language::name:z:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R *= R") + { + std::string_view data = R"( +let x : R, x=1; x*=2.3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, double, double>) + +-(language::name:x:NameProcessor) + `-(language::real:2.3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 *= R") + { + std::string_view data = R"( +let x : R^1; x*=2.3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<1ul, double>, double>) + +-(language::name:x:NameProcessor) + `-(language::real:2.3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 *= R") + { + std::string_view data = R"( +let x : R^2; x*= 6.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<2ul, double>, double>) + +-(language::name:x:NameProcessor) + `-(language::real:6.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 *= R") + { + std::string_view data = R"( +let x : R^3; x*= 3.1; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<3ul, double>, double>) + +-(language::name:x:NameProcessor) + `-(language::real:3.1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R *= Z") + { + std::string_view data = R"( +let x : R, x=1; x*=2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, double, long>) + +-(language::name:x:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 *= Z") + { + std::string_view data = R"( +let x : R^1; x *= 3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<1ul, double>, long>) + +-(language::name:x:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 *= Z") + { + std::string_view data = R"( +let x : R^2; x *= 6; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<2ul, double>, long>) + +-(language::name:x:NameProcessor) + `-(language::integer:6:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 *= Z") + { + std::string_view data = R"( +let x : R^3; x *= 4; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<3ul, double>, long>) + +-(language::name:x:NameProcessor) + `-(language::integer:4:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R *= N") + { + std::string_view data = R"( +let n : N, n=2; let x : R, x=1; x *= n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:2:ValueProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, double, unsigned long>) + +-(language::name:x:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 *= N") + { + std::string_view data = R"( +let n : N; +let x : R^1; x *= n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<1ul, double>, unsigned long>) + +-(language::name:x:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 *= N") + { + std::string_view data = R"( +let n : N; +let x : R^2; x *= n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<2ul, double>, unsigned long>) + +-(language::name:x:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 *= N") + { + std::string_view data = R"( +let n : N; +let x : R^3; x *= n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<3ul, double>, unsigned long>) + +-(language::name:x:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R *= B") + { + std::string_view data = R"( +let x : R, x=1; x *= true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, double, bool>) + +-(language::name:x:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1 *= B") + { + std::string_view data = R"( +let x : R^1; x *= true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<1ul, double>, bool>) + +-(language::name:x:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2 *= B") + { + std::string_view data = R"( +let x : R^2; x *= false; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<2ul, double>, bool>) + +-(language::name:x:NameProcessor) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3 *= B") + { + std::string_view data = R"( +let b : B; let x : R^3; x *= b; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, TinyVector<3ul, double>, bool>) + +-(language::name:x:NameProcessor) + `-(language::name:b:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("/=") + { + SECTION("Z /= Z") + { + std::string_view data = R"( +let z : Z, z=6; z/=2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:z:NameProcessor) + | `-(language::integer:6:ValueProcessor) + `-(language::divideeq_op:AffectationProcessor<language::divideeq_op, long, long>) + +-(language::name:z:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R /= R") + { + std::string_view data = R"( +let x : R, x=1; x/=2.3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::divideeq_op:AffectationProcessor<language::divideeq_op, double, double>) + +-(language::name:x:NameProcessor) + `-(language::real:2.3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Errors") + { + SECTION("Invalid affectation operator") + { + auto ast = std::make_unique<ASTNode>(); + REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast}, + "unexpected error: undefined affectation operator"); + } + + SECTION("Invalid lhs") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast}, + "unexpected error: undefined value type for affectation"); + } + + SECTION("Invalid rhs") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::eq_op>(); + ast->m_data_type = ASTNodeDataType::int_t; + + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast}, + "unexpected error: invalid implicit conversion: undefined -> Z"); + } + + SECTION("Invalid string rhs") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::eq_op>(); + ast->m_data_type = ASTNodeDataType::string_t; + + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast}, + "unexpected error: invalid implicit conversion: undefined -> string"); + } + + SECTION("Invalid string affectation operator") + { + SECTION("string -= string") + { + std::string_view data = R"( +let s : string, s="foo"; s-="bar"; +)"; + + std::string error_message = "invalid affectation operator for string"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("string *= Z") + { + std::string_view data = R"( +let s : string, s="foo"; s*=2; +)"; + + std::string error_message = "invalid affectation operator for string"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("string /= string") + { + std::string_view data = R"( + let s : string, s="foo"; s/="bar"; +)"; + + std::string error_message = "invalid affectation operator for string"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + } + + SECTION("type_id operator") + { + std::string_view data = R"( + let s :builtin_t, s = a; s *= b; +)"; + + std::string error_message = "invalid affectation operator for 'builtin_t'"; + + CHECK_AST_WITH_BUILTIN_THROWS_WITH(data, error_message); + } + + SECTION("Invalid tuple operator") + { + std::string_view data = R"( + let s :(R), s=(1,2,3); s *= 4; +)"; + + std::string error_message = "invalid affectation operator for 'tuple(R)'"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("Invalid tuple operator 2") + { + std::string_view data = R"( + let s : (builtin_t), s =(a,b); s *= b; +)"; + + std::string error_message = "invalid affectation operator for 'tuple(builtin_t)'"; + + CHECK_AST_WITH_BUILTIN_THROWS_WITH(data, error_message); + } + + SECTION("Invalid R^n -> R^m affectation") + { + SECTION("R^3 <- R^1") + { + std::string_view data = R"( +let x : R^3; let y : R^1; x = y; +)"; + + std::string error_message = "incompatible dimensions in affectation"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^3 <- R^2") + { + std::string_view data = R"( +let x : R^3; let y : R^2; x = y; +)"; + + std::string error_message = "incompatible dimensions in affectation"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^2 <- R^1") + { + std::string_view data = R"( +let x : R^2; let y : R^1; x = y; +)"; + + std::string error_message = "incompatible dimensions in affectation"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^2 <- R^3") + { + std::string_view data = R"( +let x : R^2; let y : R^3; x = y; +)"; + + std::string error_message = "incompatible dimensions in affectation"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^1 <- R^2") + { + std::string_view data = R"( +let x : R^1; let y : R^2; x = y; +)"; + + std::string error_message = "incompatible dimensions in affectation"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^1 <- R^3") + { + std::string_view data = R"( +let x : R^1; let y : R^2; x = y; +)"; + + std::string error_message = "incompatible dimensions in affectation"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + } + + SECTION("Invalid Z -> R^m affectation [non-zero]") + { + SECTION("R^3 <- Z") + { + std::string_view data = R"( +let x : R^3, x = 3; +)"; + + std::string error_message = "invalid implicit conversion: Z -> R^3"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^2 <- Z") + { + std::string_view data = R"( +let x : R^2, x = 2; +)"; + + std::string error_message = "invalid implicit conversion: Z -> R^2"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + } + + SECTION("Invalid R^d -> R^d affectation operator") + { + SECTION("R^3 <- R^3") + { + std::string_view data = R"( +let x : R^3; let y : R^3; x /= y; +)"; + + std::string error_message = "invalid affectation operator for R^3"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^2 <- R^2") + { + std::string_view data = R"( +let x : R^2; let y : R^2; x /= y; +)"; + + std::string error_message = "invalid affectation operator for R^2"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^1 <- R^1") + { + std::string_view data = R"( +let x : R^1; let y : R^1; x /= y; +)"; + + std::string error_message = "invalid affectation operator for R^1"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + } + + SECTION("Invalid R^d -> R^d *= operand") + { + SECTION("R^3 <- R^3") + { + std::string_view data = R"( +let x : R^3; let y : R^3; x *= y; +)"; + + std::string error_message = "expecting scalar operand type"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^2 <- R^2") + { + std::string_view data = R"( +let x : R^2; let y : R^2; x *= y; +)"; + + std::string error_message = "expecting scalar operand type"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + + SECTION("R^1 <- R^1") + { + std::string_view data = R"( +let x : R^1; let y : R^1; x *= y; +)"; + + std::string error_message = "expecting scalar operand type"; + + CHECK_AST_THROWS_WITH(data, error_message); + } + } + + SECTION("incorrect declarative/definition number of symbols") + { + std::string_view data = R"( +let (x,y,z):R*R*R, (x,y) = (2,3); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, + std::string{"invalid number of definition identifiers, expecting 3 found 2"}); + } + + SECTION("incorrect identifier/expression number of symbols") + { + std::string_view data = R"( +let (x,y,z):R*R*R, (x,y,z) = (2,3); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, + std::string{"invalid number of definition expressions, expecting 3 found 2"}); + } + + SECTION("incorrect identifier/expression number of symbols") + { + std::string_view data = R"( +let y:R; +let x:R, (x,y) = (2,3); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, + std::string{"unexpected variable list, expecting one identifier"}); + } + + SECTION("incorrect definition variable identifier") + { + std::string_view data = R"( +let y:R; +let x:R, y = 3; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"invalid identifier, expecting 'x'"}); + } + + SECTION("invalid definition variable identifier order") + { + std::string_view data = R"( +let (x,y):R, (y,x) = (3,2); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"invalid identifier, expecting 'x'"}); + } + } +} diff --git a/tests/test_ASTNodeArraySubscriptExpressionBuilder.cpp b/tests/test_ASTNodeArraySubscriptExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..941df56ac9d28de2aa5a211c61964b8d9ce05ee6 --- /dev/null +++ b/tests/test_ASTNodeArraySubscriptExpressionBuilder.cpp @@ -0,0 +1,90 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp> +#include <language/node_processor/ArraySubscriptProcessor.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeArraySubscriptExpressionBuilder", "[language]") +{ + SECTION("R^d component access") + { + std::unique_ptr node = std::make_unique<ASTNode>(); + + SECTION("R^1") + { + { + std::unique_ptr array_node = std::make_unique<ASTNode>(); + array_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + node->emplace_back(std::move(array_node)); + } + REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node}); + REQUIRE(bool{node->m_node_processor}); + auto& node_processor = *node->m_node_processor; + REQUIRE(typeid(node_processor).name() == typeid(ArraySubscriptProcessor<TinyVector<1>>).name()); + } + + SECTION("R^2") + { + { + std::unique_ptr array_node = std::make_unique<ASTNode>(); + array_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + node->emplace_back(std::move(array_node)); + } + REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node}); + REQUIRE(bool{node->m_node_processor}); + auto& node_processor = *node->m_node_processor; + REQUIRE(typeid(node_processor).name() == typeid(ArraySubscriptProcessor<TinyVector<2>>).name()); + } + + SECTION("R^3") + { + { + std::unique_ptr array_node = std::make_unique<ASTNode>(); + array_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + node->emplace_back(std::move(array_node)); + } + REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node}); + REQUIRE(bool{node->m_node_processor}); + auto& node_processor = *node->m_node_processor; + REQUIRE(typeid(node_processor).name() == typeid(ArraySubscriptProcessor<TinyVector<3>>).name()); + } + } + + SECTION("R^d component bad access") + { + std::unique_ptr node = std::make_unique<ASTNode>(); + + SECTION("R^d (d < 1)") + { + { + std::unique_ptr array_node = std::make_unique<ASTNode>(); + array_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 0}; + node->emplace_back(std::move(array_node)); + } + REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array dimension"); + } + SECTION("R^d (d > 3)") + { + { + std::unique_ptr array_node = std::make_unique<ASTNode>(); + array_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 4}; + node->emplace_back(std::move(array_node)); + } + REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array dimension"); + } + } + + SECTION("invalid array expression") + { + std::unique_ptr node = std::make_unique<ASTNode>(); + { + std::unique_ptr array_node = std::make_unique<ASTNode>(); + node->emplace_back(std::move(array_node)); + } + REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array type"); + } +} diff --git a/tests/test_ASTNodeBinaryOperatorExpressionBuilder.cpp b/tests/test_ASTNodeBinaryOperatorExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78a3f5f3b16bfdcb804421cc41e59a1c37abde4f --- /dev/null +++ b/tests/test_ASTNodeBinaryOperatorExpressionBuilder.cpp @@ -0,0 +1,2148 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeBinaryOperatorExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define REQUIRE_AST_THROWS_WITH(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeBinaryOperatorExpressionBuilder", "[language]") +{ + SECTION("multiply") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b*true; +false*b*true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, bool, bool>) + | +-(language::name:b:NameProcessor) + | `-(language::true_kw:ValueProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, long, bool>) + +-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, bool, bool>) + | +-(language::false_kw:ValueProcessor) + | `-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n*m*n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, unsigned long, unsigned long>) + +-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, unsigned long, unsigned long>) + | +-(language::name:n:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a*3*a; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, long, long>) + +-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3*1.2*2*false; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, double, bool>) + +-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, double, long>) + | +-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, double, double>) + | | +-(language::real:2.3:ValueProcessor) + | | `-(language::real:1.2:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1") + { + std::string_view data = R"( +let x : R^1, x = 3.7; +2*x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, double>) + | +-(language::name:x:NameProcessor) + | `-(language::real:3.7:ValueProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, long, TinyVector<1ul, double> >) + +-(language::integer:2:ValueProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2") + { + std::string_view data = R"( +let x : R^2, x = (3.2,6); +2*x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:3.2:ValueProcessor) + | `-(language::integer:6:ValueProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, long, TinyVector<2ul, double> >) + +-(language::integer:2:ValueProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3") + { + std::string_view data = R"( +let x : R^3, x = (3.2,6,1.2); +2*x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:3.2:ValueProcessor) + | +-(language::integer:6:ValueProcessor) + | `-(language::real:1.2:ValueProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, long, TinyVector<3ul, double> >) + +-(language::integer:2:ValueProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("divide") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b/true; +false/b/true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::divide_op:BinaryExpressionProcessor<language::divide_op, bool, bool>) + | +-(language::name:b:NameProcessor) + | `-(language::true_kw:ValueProcessor) + `-(language::divide_op:BinaryExpressionProcessor<language::divide_op, long, bool>) + +-(language::divide_op:BinaryExpressionProcessor<language::divide_op, bool, bool>) + | +-(language::false_kw:ValueProcessor) + | `-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n/m/n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::divide_op:BinaryExpressionProcessor<language::divide_op, unsigned long, unsigned long>) + +-(language::divide_op:BinaryExpressionProcessor<language::divide_op, unsigned long, unsigned long>) + | +-(language::name:n:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a/3/a; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::divide_op:BinaryExpressionProcessor<language::divide_op, long, long>) + +-(language::divide_op:BinaryExpressionProcessor<language::divide_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3/1.2/2/false; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::divide_op:BinaryExpressionProcessor<language::divide_op, double, bool>) + +-(language::divide_op:BinaryExpressionProcessor<language::divide_op, double, long>) + | +-(language::divide_op:BinaryExpressionProcessor<language::divide_op, double, double>) + | | +-(language::real:2.3:ValueProcessor) + | | `-(language::real:1.2:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("plus") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b+true; +false+b+true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::plus_op:BinaryExpressionProcessor<language::plus_op, bool, bool>) + | +-(language::name:b:NameProcessor) + | `-(language::true_kw:ValueProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, long, bool>) + +-(language::plus_op:BinaryExpressionProcessor<language::plus_op, bool, bool>) + | +-(language::false_kw:ValueProcessor) + | `-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n+m+n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, unsigned long, unsigned long>) + +-(language::plus_op:BinaryExpressionProcessor<language::plus_op, unsigned long, unsigned long>) + | +-(language::name:n:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a+3+a; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, long, long>) + +-(language::plus_op:BinaryExpressionProcessor<language::plus_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3+1.2+2+false; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, double, bool>) + +-(language::plus_op:BinaryExpressionProcessor<language::plus_op, double, long>) + | +-(language::plus_op:BinaryExpressionProcessor<language::plus_op, double, double>) + | | +-(language::real:2.3:ValueProcessor) + | | `-(language::real:1.2:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1") + { + std::string_view data = R"( +let x : R^1, x = 1; +let y : R^1, y = 2; +x+y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:y:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, TinyVector<1ul, double>, TinyVector<1ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2") + { + std::string_view data = R"( +let x : R^2, x = (1,2); +let y : R^2, y = (0.3,0.7); +x+y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:0.3:ValueProcessor) + | `-(language::real:0.7:ValueProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, TinyVector<2ul, double>, TinyVector<2ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let y : R^3, y = (4,3,2); +x+y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:4:ValueProcessor) + | +-(language::integer:3:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, TinyVector<3ul, double>, TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string concatenate bool") + { + std::string_view data = R"( +"foo"+true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:ConcatExpressionProcessor<bool>) + +-(language::literal:"foo":ValueProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string concatenate N") + { + std::string_view data = R"( +let n : N, n=0; +"foo"+n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::plus_op:ConcatExpressionProcessor<unsigned long>) + +-(language::literal:"foo":ValueProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string concatenate Z") + { + std::string_view data = R"( +"foo"+1; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:ConcatExpressionProcessor<long>) + +-(language::literal:"foo":ValueProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string concatenate R") + { + std::string_view data = R"( +"foo"+1.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:ConcatExpressionProcessor<double>) + +-(language::literal:"foo":ValueProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string concatenate string") + { + std::string_view data = R"( +"foo"+"bar"; +)"; + + std::string string_name = demangle(typeid(std::string{}).name()); + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:ConcatExpressionProcessor<)" + + string_name + R"( >) + +-(language::literal:"foo":ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("minus") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b-true; +false-b-true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::minus_op:BinaryExpressionProcessor<language::minus_op, bool, bool>) + | +-(language::name:b:NameProcessor) + | `-(language::true_kw:ValueProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, long, bool>) + +-(language::minus_op:BinaryExpressionProcessor<language::minus_op, bool, bool>) + | +-(language::false_kw:ValueProcessor) + | `-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n-m-n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, unsigned long, unsigned long>) + +-(language::minus_op:BinaryExpressionProcessor<language::minus_op, unsigned long, unsigned long>) + | +-(language::name:n:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a-3-a; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, long, long>) + +-(language::minus_op:BinaryExpressionProcessor<language::minus_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3-1.2-2-false; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, double, bool>) + +-(language::minus_op:BinaryExpressionProcessor<language::minus_op, double, long>) + | +-(language::minus_op:BinaryExpressionProcessor<language::minus_op, double, double>) + | | +-(language::real:2.3:ValueProcessor) + | | `-(language::real:1.2:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1") + { + std::string_view data = R"( +let x : R^1, x = 1; +let y : R^1, y = 2; +x-y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:y:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, TinyVector<1ul, double>, TinyVector<1ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2") + { + std::string_view data = R"( +let x : R^2, x = (1,2); +let y : R^2, y = (0.3,0.7); +x-y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:0.3:ValueProcessor) + | `-(language::real:0.7:ValueProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, TinyVector<2ul, double>, TinyVector<2ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let y : R^3, y = (4,3,2); +x-y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:4:ValueProcessor) + | +-(language::integer:3:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, TinyVector<3ul, double>, TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("or") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b or true; +false or b or true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::or_op:BinaryExpressionProcessor<language::or_op, bool, bool>) + | +-(language::name:b:NameProcessor) + | `-(language::true_kw:ValueProcessor) + `-(language::or_op:BinaryExpressionProcessor<language::or_op, bool, bool>) + +-(language::or_op:BinaryExpressionProcessor<language::or_op, bool, bool>) + | +-(language::false_kw:ValueProcessor) + | `-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("and") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b and true; +false and b and true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::and_op:BinaryExpressionProcessor<language::and_op, bool, bool>) + | +-(language::name:b:NameProcessor) + | `-(language::true_kw:ValueProcessor) + `-(language::and_op:BinaryExpressionProcessor<language::and_op, bool, bool>) + +-(language::and_op:BinaryExpressionProcessor<language::and_op, bool, bool>) + | +-(language::false_kw:ValueProcessor) + | `-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("xor") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b xor true; +false xor b xor true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::xor_op:BinaryExpressionProcessor<language::xor_op, bool, bool>) + | +-(language::name:b:NameProcessor) + | `-(language::true_kw:ValueProcessor) + `-(language::xor_op:BinaryExpressionProcessor<language::xor_op, bool, bool>) + +-(language::xor_op:BinaryExpressionProcessor<language::xor_op, bool, bool>) + | +-(language::false_kw:ValueProcessor) + | `-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("greater") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b > true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_op:BinaryExpressionProcessor<language::greater_op, bool, bool>) + +-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n > m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_op:BinaryExpressionProcessor<language::greater_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a > 3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_op:BinaryExpressionProcessor<language::greater_op, long, long>) + +-(language::name:a:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3 > 1.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_op:BinaryExpressionProcessor<language::greater_op, double, double>) + +-(language::real:2.3:ValueProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("lesser") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b < true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, bool, bool>) + +-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n < m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a < 3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, long, long>) + +-(language::name:a:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3 < 1.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, double, double>) + +-(language::real:2.3:ValueProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("greater or equal") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b >= true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_or_eq_op:BinaryExpressionProcessor<language::greater_or_eq_op, bool, bool>) + +-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n >= m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_or_eq_op:BinaryExpressionProcessor<language::greater_or_eq_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a >= 3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_or_eq_op:BinaryExpressionProcessor<language::greater_or_eq_op, long, long>) + +-(language::name:a:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3 >= 1.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_or_eq_op:BinaryExpressionProcessor<language::greater_or_eq_op, double, double>) + +-(language::real:2.3:ValueProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("lesser or equal") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b <= true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_or_eq_op:BinaryExpressionProcessor<language::lesser_or_eq_op, bool, bool>) + +-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n <= m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_or_eq_op:BinaryExpressionProcessor<language::lesser_or_eq_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a <= 3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_or_eq_op:BinaryExpressionProcessor<language::lesser_or_eq_op, long, long>) + +-(language::name:a:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3 <= 1.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_or_eq_op:BinaryExpressionProcessor<language::lesser_or_eq_op, double, double>) + +-(language::real:2.3:ValueProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("equal equal") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b == true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, bool, bool>) + +-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n == m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a == 3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, long, long>) + +-(language::name:a:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3 == 1.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, double, double>) + +-(language::real:2.3:ValueProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string == string") + { + std::string_view data = R"( +"foo" == "bar"; +)"; + + std::string string_name = demangle(typeid(std::string{}).name()); + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, )" + + string_name + ", " + string_name + R"( >) + +-(language::literal:"foo":ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1") + { + std::string_view data = R"( +let x : R^1, x = 1; +let y : R^1, y = 2; +x==y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:y:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, TinyVector<1ul, double>, TinyVector<1ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2") + { + std::string_view data = R"( +let x : R^2, x = (1,2); +let y : R^2, y = (0.3,0.7); +x==y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:0.3:ValueProcessor) + | `-(language::real:0.7:ValueProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, TinyVector<2ul, double>, TinyVector<2ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let y : R^3, y = (4,3,2); +x==y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:4:ValueProcessor) + | +-(language::integer:3:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, TinyVector<3ul, double>, TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("not equal") + { + SECTION("B") + { + std::string_view data = R"( +let b : B; +b != true; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, bool, bool>) + +-(language::name:b:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +let m : N; +n != m; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, unsigned long, unsigned long>) + +-(language::name:n:NameProcessor) + `-(language::name:m:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let a : Z; +a != 3; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, long, long>) + +-(language::name:a:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +2.3 != 1.2; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, double, double>) + +-(language::real:2.3:ValueProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1") + { + std::string_view data = R"( +let x : R^1, x = 1; +let y : R^1, y = 2; +x!=y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyVector<1ul, double>, long>) + | +-(language::name:y:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, TinyVector<1ul, double>, TinyVector<1ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2") + { + std::string_view data = R"( +let x : R^2, x = (1,2); +let y : R^2, y = (0.3,0.7); +x!=y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:0.3:ValueProcessor) + | `-(language::real:0.7:ValueProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, TinyVector<2ul, double>, TinyVector<2ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let y : R^3, y = (4,3,2); +x!=y; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:y:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:4:ValueProcessor) + | +-(language::integer:3:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, TinyVector<3ul, double>, TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string != string") + { + std::string_view data = R"( +"foo" != "bar"; +)"; + + std::string string_name = demangle(typeid(std::string{}).name()); + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, )" + + string_name + ", " + string_name + R"( >) + +-(language::literal:"foo":ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + } + + SECTION("Errors") + { + SECTION("Invalid binary operator type") + { + auto ast = std::make_unique<ASTNode>(); + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "unexpected error: undefined binary operator"); + } + + SECTION("Invalid string binary operators") + { + SECTION("lhs bad multiply") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::multiply_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string multiply") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::multiply_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string multiply") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::multiply_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad divide") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::divide_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string divide") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::divide_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string divide") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::divide_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad plus") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::plus_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string plus bad rhs") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::plus_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::void_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string plus") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::plus_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad minus") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::minus_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string minus") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::minus_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string minus") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::minus_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad or") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::or_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string or") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::or_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string or") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::or_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad and") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::and_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string and") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::and_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string and") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::and_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad xor") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::xor_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string xor") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::xor_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string xor") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::xor_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad >") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::greater_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string >") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::greater_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string >") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::greater_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad <") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::lesser_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string <") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::lesser_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string <") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::lesser_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad >=") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::greater_or_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string >=") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::greater_or_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string >=") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::greater_or_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad <=") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::lesser_or_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string <=") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::lesser_or_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string <=") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::lesser_or_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad ==") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::eqeq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string ==") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::eqeq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string ==") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::eqeq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("lhs bad !=") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::not_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::void_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("left string ==") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::not_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::string_t; + ast->children[1]->m_data_type = ASTNodeDataType::int_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + + SECTION("right string ==") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::not_eq_op>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->m_data_type = ASTNodeDataType::int_t; + ast->children[1]->m_data_type = ASTNodeDataType::string_t; + + REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator"); + } + } + + SECTION("invalid R^d operators") + { + SECTION("invalid operator R^1 > R^1") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^1, y = 0; +x > y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^1 >= R^1") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^1, y = 0; +x >= y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^1 < R^1") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^1, y = 0; +x < y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^1 <= R^1") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^1, y = 1; +x <= y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^1 * R^1") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^1, y = 0; +x * y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^1 / R^1") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^1, y = 0; +x / y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^2 > R^2") + { + std::string_view data = R"( +let x : R^2, x = 0; +let y : R^2, y = 0; +x > y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^2 >= R^2") + { + std::string_view data = R"( +let x : R^2, x = 0; +let y : R^2, y = 0; +x >= y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^2 < R^2") + { + std::string_view data = R"( +let x : R^2, x = 0; +let y : R^2, y = 0; +x < y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^2 <= R^2") + { + std::string_view data = R"( +let x : R^2, x = 0; +let y : R^2, y = 0; +x <= y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^2 * R^2") + { + std::string_view data = R"( +let x : R^2, x = 0; +let y : R^2, y = 0; +x * y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^2 / R^2") + { + std::string_view data = R"( +let x : R^2, x = 0; +let y : R^2, y = 0; +x / y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^3 > R^3") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^3, y = 0; +x > y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^3 >= R^3") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^3, y = 0; +x >= y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^3 < R^3") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^3, y = 0; +x < y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^3 <= R^3") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^3, y = 0; +x <= y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^3 * R^3") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^3, y = 0; +x * y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + + SECTION("invalid operator R^3 / R^3") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^3, y = 0; +x / y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "invalid binary operator"); + } + } + + SECTION("invalid operand types") + { + SECTION("incompatible operand dimensions") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^1, y = 0; +x + y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "incompatible dimensions of operands"); + } + + SECTION("incompatible operand dimensions") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^2, y = 0; +x - y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "incompatible dimensions of operands"); + } + + SECTION("incompatible operand dimensions") + { + std::string_view data = R"( +let x : R^3, x = 0; +let y : R^2, y = 0; +x == y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "incompatible dimensions of operands"); + } + + SECTION("incompatible operand dimensions") + { + std::string_view data = R"( +let x : R^1, x = 0; +let y : R^2, y = 0; +x != y; +)"; + + REQUIRE_AST_THROWS_WITH(data, "incompatible dimensions of operands"); + } + } + } +} diff --git a/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2954cd8db2e691ea2206b30b158f9596a8290081 --- /dev/null +++ b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp @@ -0,0 +1,1193 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <test_BuiltinFunctionRegister.hpp> + +#include <pegtl/string_input.hpp> + +#include <memory> +#include <unordered_map> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + test_only::test_BuiltinFunctionRegister{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define CHECK_AST_THROWS_WITH(data, expected_error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + test_only::test_BuiltinFunctionRegister{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, Catch::Matchers::Contains(expected_error)); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeBuiltinFunctionExpressionBuilder", "[language]") +{ + SECTION("R -> R") + { + SECTION("from R") + { + std::string_view data = R"( +RtoR(1.); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR:NameProcessor) + `-(language::real:1.:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from Z") + { + std::string_view data = R"( +RtoR(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from N") + { + std::string_view data = R"( +let n : N, n = 1; +RtoR(n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from B") + { + std::string_view data = R"( +RtoR(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R -> R1") + { + SECTION("from R") + { + std::string_view data = R"( +RtoR1(1.); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR1:NameProcessor) + `-(language::real:1.:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from Z") + { + std::string_view data = R"( +RtoR1(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR1:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from N") + { + std::string_view data = R"( +let n : N, n = 1; +RtoR1(n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR1:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from B") + { + std::string_view data = R"( +RtoR1(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RtoR1:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R1 -> R") + { + SECTION("from R1") + { + std::string_view data = R"( +let x : R^1, x = 2; +R1toR(x); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R1toR:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from R") + { + std::string_view data = R"( +R1toR(1.); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R1toR:NameProcessor) + `-(language::real:1.:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from Z") + { + std::string_view data = R"( +R1toR(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R1toR:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from N") + { + std::string_view data = R"( +let n : N, n = 1; +R1toR(n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R1toR:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from B") + { + std::string_view data = R"( +R1toR(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R1toR:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R2 -> R") + { + SECTION("from 0") + { + std::string_view data = R"( +R2toR(0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R2toR:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from R^2") + { + std::string_view data = R"( +let x:R^2, x = (1,2); +R2toR(x); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R2toR:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from list") + { + std::string_view data = R"( +R2toR((1,2)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R2toR:NameProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R3 -> R") + { + SECTION("from 0") + { + std::string_view data = R"( +R3toR(0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R3toR:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from R^3") + { + std::string_view data = R"( +let x:R^3, x = (1,2,4); +R3toR(x); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R3toR:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from list") + { + std::string_view data = R"( +R3toR((1,2,3)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R3toR:NameProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Z -> R") + { + SECTION("from Z") + { + std::string_view data = R"( +ZtoR(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:ZtoR:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from N") + { + std::string_view data = R"( +let n : N, n = 1; +ZtoR(n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:ZtoR:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from B") + { + std::string_view data = R"( +ZtoR(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:ZtoR:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("N -> R") + { + SECTION("from Z") + { + std::string_view data = R"( +NtoR(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:NtoR:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from N") + { + std::string_view data = R"( +let n : N, n = 1; +NtoR(n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:NtoR:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from B") + { + std::string_view data = R"( +NtoR(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:NtoR:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("B -> R") + { + SECTION("from B") + { + std::string_view data = R"( +BtoR(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:BtoR:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R*R -> B") + { + std::string_view data = R"( +RRtoB(1., 0.); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:RRtoB:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::real:1.:ValueProcessor) + `-(language::real:0.:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3*R^2 -> R") + { + SECTION("from R^3*R^2") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let y : R^2, y = (2,3); +R3R2toR(x,y); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R3R2toR:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::name:x:NameProcessor) + `-(language::name:y:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from (R,R,R)*(R,R)") + { + std::string_view data = R"( +R3R2toR((1,2,3),(3,4)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R3R2toR:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::integer:3:ValueProcessor) + `-(language::integer:4:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from (R,R,R)*(0)") + { + std::string_view data = R"( +R3R2toR((1,2,3),0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:R3R2toR:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("string -> B") + { + std::string_view data = R"( +StoB("foo"); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:StoB:NameProcessor) + `-(language::literal:"foo":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("builtin_t -> builtin_t") + { + std::string_view data = R"( +builtinToBuiltin(a); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:builtinToBuiltin:NameProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("-> tuple") + { + SECTION("B -> tuple(Z)") + { + std::string_view data = R"( +tuple_ZtoR(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_ZtoR:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(B) -> tuple(Z)") + { + std::string_view data = R"( +let t:(B), t =(true, false); +tuple_ZtoR(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_ZtoR:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N -> tuple(Z)") + { + std::string_view data = R"( +let n:N, n=1; +tuple_ZtoR(n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_ZtoR:NameProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(B) -> tuple(B)") + { + std::string_view data = R"( +let t:(B), t=(true,false); +tuple_BtoR(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_BtoR:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(N) -> tuple(N)") + { + std::string_view data = R"( +let t:(N), t=(1,3,7); +tuple_NtoR(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_NtoR:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(N) -> tuple(Z)") + { + std::string_view data = R"( +let t:(N), t=(1,3,7); +tuple_ZtoR(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_ZtoR:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z -> tuple(Z)") + { + std::string_view data = R"( +tuple_ZtoR(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_ZtoR:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(Z) -> tuple(Z)") + { + std::string_view data = R"( +let t:(Z), t=(1,3,7); +tuple_ZtoR(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_ZtoR:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z -> tuple(R)") + { + std::string_view data = R"( +tuple_RtoB(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_RtoB:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(Z) -> tuple(R)") + { + std::string_view data = R"( +let t:(Z), t = (1,2,4,6); +tuple_RtoB(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_RtoB:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R -> tuple(R)") + { + std::string_view data = R"( +tuple_RtoB(1.2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_RtoB:NameProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(R) -> tuple(R)") + { + std::string_view data = R"( +let t:(R), t = (1,2,4,6); +tuple_RtoB(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_RtoB:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("list -> tuple(R)") + { + std::string_view data = R"( +let n:N, n = 3; +tuple_RtoB((1.2, 2, true, n)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_RtoB:NameProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::real:1.2:ValueProcessor) + +-(language::integer:2:ValueProcessor) + +-(language::true_kw:ValueProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R -> tuple(string)") + { + std::string_view data = R"( +tuple_stringtoB(1.2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_stringtoB:NameProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string -> tuple(string)") + { + std::string_view data = R"( +let s:string, s = "foo"; +tuple_stringtoB(s); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_stringtoB:NameProcessor) + `-(language::name:s:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(R) -> tuple(string)") + { + std::string_view data = R"( +let t:(R), t = (1,2,4,6); +tuple_stringtoB(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_stringtoB:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(string) -> tuple(string)") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar", "foobar"); +tuple_stringtoB(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_stringtoB:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("literal -> tuple(string)") + { + std::string_view data = R"( +tuple_stringtoB("foo"); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_stringtoB:NameProcessor) + `-(language::literal:"foo":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("list -> tuple(string)") + { + std::string_view data = R"( +tuple_stringtoB(("foo",2,"bar")); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_stringtoB:NameProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::literal:"foo":ValueProcessor) + +-(language::integer:2:ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("builtin -> tuple(builtin)") + { + std::string_view data = R"( +tuple_builtinToB(a); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_builtinToB:NameProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("list -> tuple(builtin)") + { + std::string_view data = R"( +tuple_builtinToB((a,b,a)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_builtinToB:NameProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::name:a:NameProcessor) + +-(language::name:b:NameProcessor) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple(builtin) -> tuple(builtin)") + { + std::string_view data = R"( +let t:(builtin_t), t = (a,b,a); +tuple_builtinToB(t); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_builtinToB:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z -> tuple(R1)") + { + std::string_view data = R"( +tuple_R1ToR(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R1ToR:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R -> tuple(R1)") + { + std::string_view data = R"( +tuple_R1ToR(1.2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R1ToR:NameProcessor) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R1 -> tuple(R1)") + { + std::string_view data = R"( +let r:R^1, r = 3; +tuple_R1ToR(r); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R1ToR:NameProcessor) + `-(language::name:r:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("0 -> tuple(R2)") + { + std::string_view data = R"( +tuple_R2ToR(0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R2ToR:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R2 -> tuple(R2)") + { + std::string_view data = R"( +let r:R^2, r = (1,2); +tuple_R2ToR(r); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R2ToR:NameProcessor) + `-(language::name:r:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("compound_list -> tuple(R2)") + { + std::string_view data = R"( +let r:R^2, r = (1,2); +tuple_R2ToR((r,r)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R2ToR:NameProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::name:r:NameProcessor) + `-(language::name:r:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("0 -> tuple(R3)") + { + std::string_view data = R"( +tuple_R3ToR(0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R3ToR:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R3 -> tuple(R3)") + { + std::string_view data = R"( +let r:R^3, r = (1,2,3); +tuple_R3ToR(r); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:tuple_R3ToR:NameProcessor) + `-(language::name:r:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("FunctionSymbolId -> R") + { + std::string_view data = R"( +let f : R^3 -> R, x -> 0; +fidToR(f); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:fidToR:NameProcessor) + `-(language::name:f:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("errors") + { + SECTION("bad number of arguments") + { + std::string_view data = R"( +BtoR(true, false); +)"; + CHECK_AST_THROWS_WITH(data, std::string{"bad number of arguments:"}); + } + + SECTION("bad number of arguments 2") + { + std::string_view data = R"( +RRtoB(3); +)"; + CHECK_AST_THROWS_WITH(data, std::string{"bad number of arguments:"}); + } + + SECTION("invalid argument type") + { + std::string_view data = R"( +RtoR("foo"); +)"; + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R"}); + } + } +} diff --git a/tests/test_ASTNodeDataType.cpp b/tests/test_ASTNodeDataType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a7b09eb32ace24066a3264d1acb055c33364dc7 --- /dev/null +++ b/tests/test_ASTNodeDataType.cpp @@ -0,0 +1,270 @@ +#include <catch2/catch.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeDataType.hpp> + +namespace language +{ +struct integer; +struct real; +struct vector_type; +} // namespace language + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeDataType", "[language]") +{ + SECTION("dataTypeName") + { + REQUIRE(dataTypeName(ASTNodeDataType::undefined_t) == "undefined"); + REQUIRE(dataTypeName(ASTNodeDataType::bool_t) == "B"); + REQUIRE(dataTypeName(ASTNodeDataType::unsigned_int_t) == "N"); + REQUIRE(dataTypeName(ASTNodeDataType::int_t) == "Z"); + REQUIRE(dataTypeName(ASTNodeDataType::double_t) == "R"); + REQUIRE(dataTypeName(ASTNodeDataType::string_t) == "string"); + REQUIRE(dataTypeName(ASTNodeDataType::typename_t) == "typename"); + REQUIRE(dataTypeName(ASTNodeDataType::void_t) == "void"); + REQUIRE(dataTypeName(ASTNodeDataType::function_t) == "function"); + REQUIRE(dataTypeName(ASTNodeDataType::builtin_function_t) == "builtin_function"); + REQUIRE(dataTypeName(ASTNodeDataType::list_t) == "list"); + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}) == + "tuple(B)"); + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}) == + "tuple(N)"); + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}) == + "tuple(Z)"); + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}) == + "tuple(R)"); + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}) == + "tuple(R)"); + + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::type_name_id_t, 1}) == "type_name_id"); + + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::type_id_t, "user_type"}) == "user_type"); + + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::vector_t, 1}) == "R^1"); + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::vector_t, 2}) == "R^2"); + REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::vector_t, 3}) == "R^3"); + } + + SECTION("promotion") + { + REQUIRE(dataTypePromotion(ASTNodeDataType::undefined_t, ASTNodeDataType::undefined_t) == + ASTNodeDataType::undefined_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::void_t, ASTNodeDataType::double_t) == ASTNodeDataType::undefined_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::undefined_t) == ASTNodeDataType::undefined_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::bool_t) == ASTNodeDataType::double_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::unsigned_int_t) == ASTNodeDataType::double_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::int_t) == ASTNodeDataType::double_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::unsigned_int_t) == + ASTNodeDataType::unsigned_int_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::bool_t) == ASTNodeDataType::int_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::bool_t) == + ASTNodeDataType::unsigned_int_t); + + REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::bool_t) == ASTNodeDataType::string_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::int_t) == ASTNodeDataType::string_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::unsigned_int_t) == ASTNodeDataType::string_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::double_t) == ASTNodeDataType::string_t); + + REQUIRE(dataTypePromotion(ASTNodeDataType::bool_t, ASTNodeDataType::string_t) == ASTNodeDataType::undefined_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::string_t) == ASTNodeDataType::undefined_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::string_t) == + ASTNodeDataType::undefined_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::string_t) == ASTNodeDataType::undefined_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::bool_t, ASTNodeDataType::vector_t) == ASTNodeDataType::vector_t); + REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::vector_t) == ASTNodeDataType::vector_t); + } + + SECTION("getVectorDataType") + { + std::unique_ptr type_node = std::make_unique<ASTNode>(); + type_node->set_type<language::vector_type>(); + + type_node->emplace_back(std::make_unique<ASTNode>()); + + { + std::unique_ptr dimension_node = std::make_unique<ASTNode>(); + dimension_node->set_type<language::integer>(); + dimension_node->source = "17"; + auto& source = dimension_node->source; + dimension_node->m_begin = TAO_PEGTL_NAMESPACE::internal::iterator{&source[0]}; + dimension_node->m_end = TAO_PEGTL_NAMESPACE::internal::iterator{&source[source.size()]}; + type_node->emplace_back(std::move(dimension_node)); + } + + SECTION("good node") + { + REQUIRE(getVectorDataType(*type_node) == ASTNodeDataType::vector_t); + REQUIRE(getVectorDataType(*type_node).dimension() == 17); + } + + SECTION("bad node type") + { + type_node->set_type<language::integer>(); + REQUIRE_THROWS_WITH(getVectorDataType(*type_node), "unexpected node type"); + } + + SECTION("bad children size 1") + { + type_node->children.clear(); + REQUIRE_THROWS_WITH(getVectorDataType(*type_node), "unexpected node type"); + } + + SECTION("bad children size 1") + { + type_node->children.emplace_back(std::unique_ptr<ASTNode>()); + REQUIRE_THROWS_WITH(getVectorDataType(*type_node), "unexpected node type"); + } + + SECTION("bad dimension type") + { + type_node->children[1]->set_type<language::real>(); + REQUIRE_THROWS_WITH(getVectorDataType(*type_node), "unexpected non integer constant dimension"); + } + } + + SECTION("isNaturalConversion") + { + SECTION("-> B") + { + REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::bool_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::bool_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::bool_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::bool_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::bool_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::bool_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::bool_t)); + } + + SECTION("-> N") + { + REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::unsigned_int_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::unsigned_int_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::unsigned_int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::unsigned_int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::unsigned_int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::unsigned_int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::unsigned_int_t)); + } + + SECTION("-> Z") + { + REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::int_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::int_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::int_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::int_t)); + } + + SECTION("-> R") + { + REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::double_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::double_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::double_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::double_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::double_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::double_t)); + REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::double_t)); + } + + SECTION("-> string") + { + REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::string_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::string_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::string_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::string_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::string_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::string_t)); + REQUIRE(isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::string_t)); + } + + SECTION("-> tuple") + { + REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}})); + REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::unsigned_int_t}})); + REQUIRE( + not isNaturalConversion(ASTNodeDataType::int_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}})); + + REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::unsigned_int_t}})); + REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::unsigned_int_t}})); + + REQUIRE( + isNaturalConversion(ASTNodeDataType::bool_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}})); + REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::double_t}})); + REQUIRE( + isNaturalConversion(ASTNodeDataType::unsigned_int_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}})); + REQUIRE( + isNaturalConversion(ASTNodeDataType::double_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}})); + REQUIRE( + not isNaturalConversion(ASTNodeDataType::string_t, + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}})); + } + + SECTION("-> vector") + { + REQUIRE(not isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1})); + + REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 1}, + ASTNodeDataType{ASTNodeDataType::vector_t, 1})); + REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 2}, + ASTNodeDataType{ASTNodeDataType::vector_t, 1})); + REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 3}, + ASTNodeDataType{ASTNodeDataType::vector_t, 1})); + + REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 1}, + ASTNodeDataType{ASTNodeDataType::vector_t, 2})); + REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 2}, + ASTNodeDataType{ASTNodeDataType::vector_t, 2})); + REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 3}, + ASTNodeDataType{ASTNodeDataType::vector_t, 2})); + + REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 1}, + ASTNodeDataType{ASTNodeDataType::vector_t, 3})); + REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 2}, + ASTNodeDataType{ASTNodeDataType::vector_t, 3})); + REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 3}, + ASTNodeDataType{ASTNodeDataType::vector_t, 3})); + } + + SECTION("-> type_id") + { + REQUIRE(not isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + REQUIRE( + not isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + + REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}, + ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"})); + + REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}, + ASTNodeDataType{ASTNodeDataType::type_id_t, "bar"})); + } + } +} diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e44625e1ef31b116954e7b6859b1409873b6e11 --- /dev/null +++ b/tests/test_ASTNodeDataTypeBuilder.cpp @@ -0,0 +1,2042 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <language/utils/TypeDescriptor.hpp> +#include <utils/Exceptions.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::data_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t, + "builtin_t"}; +const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>; + +#define CHECK_AST_WITH_BUILTIN(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + SymbolTable& symbol_table = *ast->m_symbol_table; \ + auto [i_symbol, success] = symbol_table.add(builtin_data_type.nameOfTypeId(), ast->begin()); \ + if (not success) { \ + throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing"); \ + } \ + \ + i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t); \ + i_symbol->attributes().setIsInitialized(); \ + i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size(); \ + symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::data_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeDataTypeBuilder", "[language]") +{ + SECTION("module") + { + std::string_view data = R"( +import a_module_name; +)"; + + std::string_view result = R"( +(root:void) + `-(language::import_instruction:void) + `-(language::module_name:string) +)"; + + CHECK_AST(data, result); + } + + SECTION("integer") + { + std::string_view data = R"( +1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 1") + { + std::string_view data = R"( +1.3; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:1.3:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 2") + { + std::string_view data = R"( +.5; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:.5:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 3") + { + std::string_view data = R"( +5e-1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:5e-1:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 4") + { + std::string_view data = R"( +2e+1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:2e+1:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 5") + { + std::string_view data = R"( +2e1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:2e1:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 6") + { + std::string_view data = R"( +5.e-1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:5.e-1:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 7") + { + std::string_view data = R"( +5.e+1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:5.e+1:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 8") + { + std::string_view data = R"( +3.4e+1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:3.4e+1:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("real 9") + { + std::string_view data = R"( +.231e1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::real:.231e1:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("true") + { + std::string_view data = R"( +true; +)"; + + std::string_view result = R"( +(root:void) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("false") + { + std::string_view data = R"( +false; +)"; + + std::string_view result = R"( +(root:void) + `-(language::false_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("block") + { + std::string_view data = R"( +{ + 1; + 2.3; +} +)"; + + std::string_view result = R"( +(root:void) + `-(language::block:void) + +-(language::integer:1:Z) + `-(language::real:2.3:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("compound") + { + SECTION("declaration") + { + std::string_view data = R"( +let (x,b,n,s) : R*B*N*string; +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:typename) + +-(language::name_list:list) + | +-(language::name:x:R) + | +-(language::name:b:B) + | +-(language::name:n:N) + | `-(language::name:s:string) + `-(language::type_expression:typename) + +-(language::R_set:typename) + +-(language::B_set:typename) + +-(language::N_set:typename) + `-(language::string_type:typename) +)"; + + CHECK_AST(data, result); + } + + SECTION("errors") + { + SECTION("invalid array subscript") + { + std::string_view data = R"( +let x : R; x[2]; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, "invalid types 'R[Z]' for array subscript"); + } + + SECTION("too many variables") + { + std::string_view data = R"( +let (x,b,n,s,t) : R*B*N*string; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, "number of product spaces (4) R*B*N*string differs from " + "number of variables (5) (x,b,n,s,t) "); + } + + SECTION("too few variables") + { + std::string_view data = R"( +let (x,b,n) : R*B*N*string; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, "number of product spaces (4) R*B*N*string differs from " + "number of variables (3) (x,b,n) "); + } + + SECTION("unexpected variable list") + { + std::string_view data = R"( +let (x,y) : R; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, "unexpected variable list for single space"); + } + + SECTION("invalid R-list -> R^d") + { + std::string_view data = R"( +let square : R -> R^3, x -> (x, x*x); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, + "expecting 3 scalar expressions or an R^3, found 2 scalar expressions"); + } + } + } + + SECTION("let declaration") + { + SECTION("tuples") + { + SECTION("B tuples") + { + std::string_view data = R"( +let t : (B), t = (true, false); +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:tuple(B)) + +-(language::name:t:tuple(B)) + +-(language::tuple_type_specifier:tuple(B)) + | `-(language::B_set:typename) + +-(language::name:t:tuple(B)) + `-(language::expression_list:list) + +-(language::true_kw:B) + `-(language::false_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("N tuples") + { + std::string_view data = R"( +let t : (N), t = (1, 2, 3, 5); +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:tuple(N)) + +-(language::name:t:tuple(N)) + +-(language::tuple_type_specifier:tuple(N)) + | `-(language::N_set:typename) + +-(language::name:t:tuple(N)) + `-(language::expression_list:list) + +-(language::integer:1:Z) + +-(language::integer:2:Z) + +-(language::integer:3:Z) + `-(language::integer:5:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z tuples") + { + std::string_view data = R"( +let n : N, n = 3; +let t : (Z), t = (2, n, true); +)"; + + std::string_view result = R"( +(root:void) + +-(language::var_declaration:N) + | +-(language::name:n:N) + | +-(language::N_set:typename) + | +-(language::name:n:N) + | `-(language::integer:3:Z) + `-(language::var_declaration:tuple(Z)) + +-(language::name:t:tuple(Z)) + +-(language::tuple_type_specifier:tuple(Z)) + | `-(language::Z_set:typename) + +-(language::name:t:tuple(Z)) + `-(language::expression_list:list) + +-(language::integer:2:Z) + +-(language::name:n:N) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("R tuples") + { + std::string_view data = R"( +let t : (R), t = (2, 3.1, 5); +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:tuple(R)) + +-(language::name:t:tuple(R)) + +-(language::tuple_type_specifier:tuple(R)) + | `-(language::R_set:typename) + +-(language::name:t:tuple(R)) + `-(language::expression_list:list) + +-(language::integer:2:Z) + +-(language::real:3.1:R) + `-(language::integer:5:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^d tuples") + { + std::string_view data = R"( +let a : R^2, a = (2,3.1); +let t1 : (R^2), t1 = (a, (1,2), 0); +let t2 : (R^3), t2 = (0, 0); +)"; + + std::string_view result = R"( +(root:void) + +-(language::var_declaration:R^2) + | +-(language::name:a:R^2) + | +-(language::vector_type:typename) + | | +-(language::R_set:typename) + | | `-(language::integer:2:Z) + | +-(language::name:a:R^2) + | `-(language::expression_list:list) + | +-(language::integer:2:Z) + | `-(language::real:3.1:R) + +-(language::var_declaration:tuple(R^2)) + | +-(language::name:t1:tuple(R^2)) + | +-(language::tuple_type_specifier:tuple(R^2)) + | | `-(language::vector_type:typename) + | | +-(language::R_set:typename) + | | `-(language::integer:2:Z) + | +-(language::name:t1:tuple(R^2)) + | `-(language::expression_list:list) + | +-(language::name:a:R^2) + | +-(language::tuple_expression:list) + | | +-(language::integer:1:Z) + | | `-(language::integer:2:Z) + | `-(language::integer:0:Z) + `-(language::var_declaration:tuple(R^3)) + +-(language::name:t2:tuple(R^3)) + +-(language::tuple_type_specifier:tuple(R^3)) + | `-(language::vector_type:typename) + | +-(language::R_set:typename) + | `-(language::integer:3:Z) + +-(language::name:t2:tuple(R^3)) + `-(language::expression_list:list) + +-(language::integer:0:Z) + `-(language::integer:0:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("string tuples") + { + std::string_view data = R"( +let t : (string), t = ("foo", "bar"); +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:tuple(string)) + +-(language::name:t:tuple(string)) + +-(language::tuple_type_specifier:tuple(string)) + | `-(language::string_type:typename) + +-(language::name:t:tuple(string)) + `-(language::expression_list:list) + +-(language::literal:"foo":string) + `-(language::literal:"bar":string) +)"; + + CHECK_AST(data, result); + } + + SECTION("type_id tuples") + { + std::string_view data = R"( +// invalid conversion just checking grammar +let t : (builtin_t), t= (1,2,3); +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:tuple(builtin_t)) + +-(language::name:t:tuple(builtin_t)) + +-(language::tuple_type_specifier:tuple(builtin_t)) + | `-(language::type_name_id:typename) + +-(language::name:t:tuple(builtin_t)) + `-(language::expression_list:list) + +-(language::integer:1:Z) + +-(language::integer:2:Z) + `-(language::integer:3:Z) +)"; + + CHECK_AST_WITH_BUILTIN(data, result); + } + + SECTION("errors") + { + SECTION("type_id") + { + std::string_view data = R"( +let t : builtin_t; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, "undefined type identifier"); + } + + SECTION("type_id 2") + { + std::string_view data = R"( +let a: R, a = 3; +let t : a; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, + "invalid type identifier, 'a' was previously defined as a 'R'"); + } + + SECTION("type_id tuples") + { + std::string_view data = R"( +let t : (builtin_t); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, "undefined type identifier"); + } + + SECTION("type_id tuples 2") + { + std::string_view data = R"( +let a: R, a = 3; +let t : (a); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, + "invalid type identifier, 'a' was previously defined as a 'R'"); + } + } + } + + SECTION("R^d-functions") + { + SECTION("vector function") + { + std::string_view data = R"( +let double : R^2 -> R^2, x -> 2*x; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:double:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("R-list -> R^d") + { + std::string_view data = R"( +let square : R -> R^2, x -> (x, x*x); +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:square:function) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R-functions") + { + SECTION("multiple variable") + { + std::string_view data = R"( +let weird : R^2*R -> R, (x,y) -> x[0]-y*x[1]; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:weird:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("multiple variable") + { + std::string_view data = R"( +let substract : R*R -> R, (x,y) -> x-y; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:substract:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("multiple values") + { + std::string_view data = R"( +let square : R -> R*R, x -> (x,x*x); +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:square:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("name -> expression") + { + std::string_view data = R"( +let f : R -> R, x -> x; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:f:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("name list -> expression") + { + std::string_view data = R"( +let f : R -> R, (x) -> (x+2)/2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:f:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("name -> expression list") + { + std::string_view data = R"( +let f : R -> R, x -> (x*x); +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:f:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("name list -> expression list") + { + std::string_view data = R"( +let f : R -> R, (x) -> (x+1); +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:f:function) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Z-functions") + { + std::string_view data = R"( +let f : Z -> Z, z -> z-1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:f:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("N-functions") + { + std::string_view data = R"( +let f : N -> N, x -> (x+1)/2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:f:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("B-functions") + { + std::string_view data = R"( +let f : N*B -> B, (n,b) -> (n>3) and b; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:f:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("string-functions") + { + std::string_view data = R"( +let cat : string*N -> string, (s,n) -> s+n; +)"; + + std::string_view result = R"( +(root:void) + `-(language::fct_declaration:void) + `-(language::name:cat:function) +)"; + + CHECK_AST(data, result); + } + + SECTION("errors") + { + SECTION("wrong parameter number") + { + std::string_view data = R"( +let f : R*Z -> B, x -> 3; +)"; + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error); + } + + SECTION("wrong parameter number 2") + { + std::string_view data = R"( +let f : R -> B, (x,y) -> 3; +)"; + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error); + } + + SECTION("wrong image size") + { + std::string_view data = R"( +let f : R*Z -> B, (x,z) -> (3, x); +)"; + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, + "number of image spaces (1) B differs from number of expressions (2) (3, x)"); + } + + SECTION("wrong image size 2") + { + std::string_view data = R"( +let f : R -> R*R, x -> x*x*x; +)"; + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, + "number of image spaces (2) R*R differs from number of expressions (1) x*x*x"); + } + } + } + + SECTION("function evaluation") + { + SECTION("R^d-functions") + { + SECTION("single argument") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> (x[0]+1, x[1]-2); +let x : R^2, x = (1,2); +x = f(x); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:f:function) + +-(language::var_declaration:R^2) + | +-(language::name:x:R^2) + | +-(language::vector_type:typename) + | | +-(language::R_set:typename) + | | `-(language::integer:2:Z) + | +-(language::name:x:R^2) + | `-(language::expression_list:list) + | +-(language::integer:1:Z) + | `-(language::integer:2:Z) + `-(language::eq_op:R^2) + +-(language::name:x:R^2) + `-(language::function_evaluation:R^2) + +-(language::name:f:function) + `-(language::name:x:R^2) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("R-functions") + { + SECTION("single argument") + { + std::string_view data = R"( +let incr : R -> R, x -> x+1; +let x : R, x = incr(3); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:incr:function) + `-(language::var_declaration:R) + +-(language::name:x:R) + +-(language::R_set:typename) + +-(language::name:x:R) + `-(language::function_evaluation:R) + +-(language::name:incr:function) + `-(language::integer:3:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("multiple variable") + { + std::string_view data = R"( +let substract : R*R -> R, (x,y) -> x-y; +let diff : R, diff = substract(3,2); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:substract:function) + `-(language::var_declaration:R) + +-(language::name:diff:R) + +-(language::R_set:typename) + +-(language::name:diff:R) + `-(language::function_evaluation:R) + +-(language::name:substract:function) + `-(language::function_argument_list:list) + +-(language::integer:3:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Z-functions") + { + std::string_view data = R"( +let incr : Z -> Z, z -> z+1; +let z : Z, z = incr(3); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:incr:function) + `-(language::var_declaration:Z) + +-(language::name:z:Z) + +-(language::Z_set:typename) + +-(language::name:z:Z) + `-(language::function_evaluation:Z) + +-(language::name:incr:function) + `-(language::integer:3:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("N-function") + { + std::string_view data = R"( +let double : N -> N, n -> 2*n; +let n : N, n = double(3); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:double:function) + `-(language::var_declaration:N) + +-(language::name:n:N) + +-(language::N_set:typename) + +-(language::name:n:N) + `-(language::function_evaluation:N) + +-(language::name:double:function) + `-(language::integer:3:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("B-function") + { + std::string_view data = R"( +let greater_than_2 : R -> B, x -> x>2; +let b : B, b = greater_than_2(3); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:greater_than_2:function) + `-(language::var_declaration:B) + +-(language::name:b:B) + +-(language::B_set:typename) + +-(language::name:b:B) + `-(language::function_evaluation:B) + +-(language::name:greater_than_2:function) + `-(language::integer:3:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("string-function") + { + std::string_view data = R"( +let cat : string*string -> string, (s,t) -> s+t; +let s : string, s = cat("foo", "bar"); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:cat:function) + `-(language::var_declaration:string) + +-(language::name:s:string) + +-(language::string_type:typename) + +-(language::name:s:string) + `-(language::function_evaluation:string) + +-(language::name:cat:function) + `-(language::function_argument_list:list) + +-(language::literal:"foo":string) + `-(language::literal:"bar":string) +)"; + + CHECK_AST(data, result); + } + + SECTION("compound return function") + { + std::string_view data = R"( +let x_x2 : R -> R*R, x -> (x,x*x); +let (x,x2) : R*R, (x,x2) = x_x2(3); +)"; + + std::string_view result = R"( +(root:void) + +-(language::fct_declaration:void) + | `-(language::name:x_x2:function) + `-(language::var_declaration:typename) + +-(language::name_list:list) + | +-(language::name:x:R) + | `-(language::name:x2:R) + +-(language::type_expression:typename) + | +-(language::R_set:typename) + | `-(language::R_set:typename) + +-(language::name_list:list) + | +-(language::name:x:R) + | `-(language::name:x2:R) + `-(language::function_evaluation:typename) + +-(language::name:x_x2:function) + `-(language::integer:3:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("errors") + { + SECTION("not a function") + { + std::string_view data = R"( +let not_a_function : R, not_a_function = 3; +not_a_function(2,3); +)"; + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + + REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error); + } + } + } + + SECTION("ostream") + { + std::string_view data = R"( +cout << "cout\n"; +cerr << "cerr\n"; +clog << "clog\n"; +)"; + + std::string_view result = R"( +(root:void) + +-(language::cout_kw:void) + | `-(language::literal:"cout\n":string) + +-(language::cerr_kw:void) + | `-(language::literal:"cerr\n":string) + `-(language::clog_kw:void) + `-(language::literal:"clog\n":string) +)"; + + CHECK_AST(data, result); + } + + SECTION("for-statement") + { + std::string_view data = R"( +for (let i : N, i=0; i<3; ++i){ + cout << i << "\n"; +} +)"; + + std::string_view result = R"( +(root:void) + `-(language::for_statement:void) + +-(language::var_declaration:N) + | +-(language::name:i:N) + | +-(language::N_set:typename) + | +-(language::name:i:N) + | `-(language::integer:0:Z) + +-(language::lesser_op:B) + | +-(language::name:i:N) + | `-(language::integer:3:Z) + +-(language::unary_plusplus:N) + | `-(language::name:i:N) + `-(language::cout_kw:void) + +-(language::name:i:N) + `-(language::literal:"\n":string) +)"; + + CHECK_AST(data, result); + } + + SECTION("B set") + { + std::string_view data = R"( +let b:B; +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:B) + +-(language::name:b:B) + `-(language::B_set:typename) +)"; + + CHECK_AST(data, result); + } + + SECTION("N set") + { + std::string_view data = R"( +let n :N; +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:N) + +-(language::name:n:N) + `-(language::N_set:typename) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z set") + { + std::string_view data = R"( +let z:Z; +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:Z) + +-(language::name:z:Z) + `-(language::Z_set:typename) +)"; + + CHECK_AST(data, result); + } + + SECTION("R set") + { + std::string_view data = R"( +let r:R; +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:R) + +-(language::name:r:R) + `-(language::R_set:typename) +)"; + + CHECK_AST(data, result); + } + + SECTION("string") + { + std::string_view data = R"( +let s: string; +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:string) + +-(language::name:s:string) + `-(language::string_type:typename) +)"; + + CHECK_AST(data, result); + } + + SECTION("type_id") + { + std::string_view data = R"( +// invalid conversion just checking grammar +let t : builtin_t, t= 1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::var_declaration:builtin_t) + +-(language::name:t:builtin_t) + +-(language::type_name_id:typename) + +-(language::name:t:builtin_t) + `-(language::integer:1:Z) +)"; + + CHECK_AST_WITH_BUILTIN(data, result); + } + + SECTION("continue") + { + std::string_view data = R"( +continue; +)"; + + std::string_view result = R"( +(root:void) + `-(language::continue_kw:void) +)"; + + CHECK_AST(data, result); + } + + SECTION("break") + { + std::string_view data = R"( +break; +)"; + + std::string_view result = R"( +(root:void) + `-(language::break_kw:void) +)"; + + CHECK_AST(data, result); + } + + SECTION("eq_op") + { + std::string_view data = R"( +let a:N; +a = 1; +)"; + + std::string_view result = R"( +(root:void) + +-(language::var_declaration:N) + | +-(language::name:a:N) + | `-(language::N_set:typename) + `-(language::eq_op:N) + +-(language::name:a:N) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("multiplyeq_op") + { + std::string_view data = R"( +let a:N, a = 1; +a *= 1.2; +)"; + + std::string_view result = R"( +(root:void) + +-(language::var_declaration:N) + | +-(language::name:a:N) + | +-(language::N_set:typename) + | +-(language::name:a:N) + | `-(language::integer:1:Z) + `-(language::multiplyeq_op:N) + +-(language::name:a:N) + `-(language::real:1.2:R) +)"; + + CHECK_AST(data, result); + } + + SECTION("divideeq_op") + { + std::string_view data = R"( +let a:R, a = 3; +a /= 2; +)"; + + std::string_view result = R"( +(root:void) + +-(language::var_declaration:R) + | +-(language::name:a:R) + | +-(language::R_set:typename) + | +-(language::name:a:R) + | `-(language::integer:3:Z) + `-(language::divideeq_op:R) + +-(language::name:a:R) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("pluseq_op") + { + std::string_view data = R"( +let a :Z, a = 3; +a += 2; +)"; + + std::string_view result = R"( +(root:void) + +-(language::var_declaration:Z) + | +-(language::name:a:Z) + | +-(language::Z_set:typename) + | +-(language::name:a:Z) + | `-(language::integer:3:Z) + `-(language::pluseq_op:Z) + +-(language::name:a:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("minuseq_op") + { + std::string_view data = R"( +let a:Z, a = 1; +a -= 2; +)"; + + std::string_view result = R"( +(root:void) + +-(language::var_declaration:Z) + | +-(language::name:a:Z) + | +-(language::Z_set:typename) + | +-(language::name:a:Z) + | `-(language::integer:1:Z) + `-(language::minuseq_op:Z) + +-(language::name:a:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("for simple") + { + std::string_view data = R"( +for (;;); +)"; + + std::string_view result = R"( +(root:void) + `-(language::for_statement:void) + +-(language::for_init:void) + +-(language::for_test:B) + +-(language::for_post:void) + `-(language::for_statement_block:void) +)"; + + CHECK_AST(data, result); + } + + SECTION("for std") + { + std::string_view data = R"( +for (let i:Z, i=0; i<3; i += 1) { i += 2; } +)"; + + std::string_view result = R"( +(root:void) + `-(language::for_statement:void) + +-(language::var_declaration:Z) + | +-(language::name:i:Z) + | +-(language::Z_set:typename) + | +-(language::name:i:Z) + | `-(language::integer:0:Z) + +-(language::lesser_op:B) + | +-(language::name:i:Z) + | `-(language::integer:3:Z) + +-(language::pluseq_op:Z) + | +-(language::name:i:Z) + | `-(language::integer:1:Z) + `-(language::pluseq_op:Z) + +-(language::name:i:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("empty block") + { + std::string_view data = R"( +{} +)"; + + std::string_view result = R"( +(root:void) +)"; + + CHECK_AST(data, result); + } + + SECTION("block") + { + std::string_view data = R"( +{ + 3; +} +)"; + + std::string_view result = R"( +(root:void) + `-(language::block:void) + `-(language::integer:3:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("if statements") + { + SECTION("empty if") + { + std::string_view data = R"( +if (true); +)"; + + std::string_view result = R"( +(root:void) + `-(language::if_statement:void) + +-(language::true_kw:B) + `-(language::statement_block:void) +)"; + + CHECK_AST(data, result); + } + + SECTION("if else") + { + std::string_view data = R"( +if (true) + 1; +else + 2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::if_statement:void) + +-(language::true_kw:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("if else simplify block") + { + std::string_view data = R"( +if (true) { + 1; +} else { + 2; +} +)"; + + std::string_view result = R"( +(root:void) + `-(language::if_statement:void) + +-(language::true_kw:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("if block") + { + std::string_view data = R"( +if (true) { + 1; + 2; +} +)"; + + std::string_view result = R"( +(root:void) + `-(language::if_statement:void) + +-(language::true_kw:B) + `-(language::block:void) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("if invalid condition") + { + std::string_view data = R"( +if ("string"); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error); + } + } + + SECTION("while statements") + { + SECTION("empty while") + { + std::string_view data = R"( +while (true); +)"; + + std::string_view result = R"( +(root:void) + `-(language::while_statement:void) + +-(language::true_kw:B) + `-(language::statement_block:void) +)"; + + CHECK_AST(data, result); + } + + SECTION("simple while") + { + std::string_view data = R"( +while (true) 1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::while_statement:void) + +-(language::true_kw:B) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("while simplified block") + { + std::string_view data = R"( +while (true) { + 1; +} +)"; + + std::string_view result = R"( +(root:void) + `-(language::while_statement:void) + +-(language::true_kw:B) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("while block_statement") + { + std::string_view data = R"( +while (true) { + 1; + 2; +} +)"; + + std::string_view result = R"( +(root:void) + `-(language::while_statement:void) + +-(language::true_kw:B) + `-(language::block:void) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("while invalid condition") + { + std::string_view data = R"( +while ("string"); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error); + } + } + + SECTION("do-while statements") + { + SECTION("empty do-while") + { + std::string_view data = R"( +do ; while (true); +)"; + + std::string_view result = R"( +(root:void) + `-(language::do_while_statement:void) + +-(language::statement_block:void) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("simple do-while") + { + std::string_view data = R"( +do 1; while (true); +)"; + + std::string_view result = R"( +(root:void) + `-(language::do_while_statement:void) + +-(language::integer:1:Z) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("do-while simplified block") + { + std::string_view data = R"( +do { + 1; +} while (true); +)"; + + std::string_view result = R"( +(root:void) + `-(language::do_while_statement:void) + +-(language::integer:1:Z) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("do-while block") + { + std::string_view data = R"( +do { + 1; + 2; +} while (true); +)"; + + std::string_view result = R"( +(root:void) + `-(language::do_while_statement:void) + +-(language::block:void) + | +-(language::integer:1:Z) + | `-(language::integer:2:Z) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("do-while invalid condition") + { + std::string_view data = R"( +do 1; while ("string"); + )"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error); + } + } + + SECTION("boolean statements") + { + SECTION("unary not") + { + std::string_view data = R"( +not false; +)"; + + std::string_view result = R"( +(root:void) + `-(language::unary_not:B) + `-(language::false_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("lesser op") + { + std::string_view data = R"( +1<2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::lesser_op:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("lesser_or_eq op") + { + std::string_view data = R"( +1<=2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::lesser_or_eq_op:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("greater op") + { + std::string_view data = R"( +1>2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::greater_op:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("greater_or_eq op") + { + std::string_view data = R"( +1>=2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::greater_or_eq_op:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("eqeq op") + { + std::string_view data = R"( +1==2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::eqeq_op:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("not_eq op") + { + std::string_view data = R"( +1!=2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::not_eq_op:B) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("and op") + { + std::string_view data = R"( +false and true; +)"; + + std::string_view result = R"( +(root:void) + `-(language::and_op:B) + +-(language::false_kw:B) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("or op") + { + std::string_view data = R"( +false or true; +)"; + + std::string_view result = R"( +(root:void) + `-(language::or_op:B) + +-(language::false_kw:B) + `-(language::true_kw:B) +)"; + + CHECK_AST(data, result); + } + + SECTION("xor op") + { + std::string_view data = R"( +true xor false; +)"; + + std::string_view result = R"( +(root:void) + `-(language::xor_op:B) + +-(language::true_kw:B) + `-(language::false_kw:B) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("unary operators") + { + SECTION("unary minus") + { + std::string_view data = R"( +- 1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::unary_minus:Z) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("unary plusplus") + { + std::string_view data = R"( +++1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::unary_plusplus:Z) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("unary minusminus") + { + std::string_view data = R"( +--1; +)"; + + std::string_view result = R"( +(root:void) + `-(language::unary_minusminus:Z) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("post plusplus") + { + std::string_view data = R"( +1++; +)"; + + std::string_view result = R"( +(root:void) + `-(language::post_plusplus:Z) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("post minusminus") + { + std::string_view data = R"( +1--; +)"; + + std::string_view result = R"( +(root:void) + `-(language::post_minusminus:Z) + `-(language::integer:1:Z) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("binary operators") + { + SECTION("plus") + { + std::string_view data = R"( +1+2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::plus_op:Z) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("minus") + { + std::string_view data = R"( +1-2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::minus_op:Z) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("multiply") + { + std::string_view data = R"( +1*2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::multiply_op:Z) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("divide") + { + std::string_view data = R"( +1/2; +)"; + + std::string_view result = R"( +(root:void) + `-(language::divide_op:Z) + +-(language::integer:1:Z) + `-(language::integer:2:Z) +)"; + + CHECK_AST(data, result); + } + + SECTION("invalid operands") + { + std::string_view data = R"( +1+"string"; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error); + } + } +} diff --git a/tests/test_ASTNodeDataTypeChecker.cpp b/tests/test_ASTNodeDataTypeChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ce833b6d43cecaaadf28086435378c0a6788933 --- /dev/null +++ b/tests/test_ASTNodeDataTypeChecker.cpp @@ -0,0 +1,51 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDataTypeChecker.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeDataTypeChecker", "[language]") +{ + SECTION("everything ok: nothrow") + { + std::string_view data = R"( +for(let i:Z, i=0; i<10; ++i) { + cout << "i=" << i; + cout<< "\n"; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + REQUIRE_NOTHROW(ASTNodeDataTypeChecker{*ast}); + } + + SECTION("everything uninitialized node type") + { + std::string_view data = R"( +for(let i:Z, i=0; i<10; ++i) { + cout << "i=" << i; + cout<< "\n"; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ast->children[0]->m_data_type = ASTNodeDataType::undefined_t; + + REQUIRE_THROWS_AS(ASTNodeDataTypeChecker{*ast}, parse_error); + } +} diff --git a/tests/test_ASTNodeDataTypeFlattener.cpp b/tests/test_ASTNodeDataTypeFlattener.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dae7437d920694f63e544aca15dc3c4e6fdb8e84 --- /dev/null +++ b/tests/test_ASTNodeDataTypeFlattener.cpp @@ -0,0 +1,158 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDataTypeFlattener.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeDataTypeFlattener", "[language]") +{ + SECTION("simple types") + { + SECTION("B") + { + std::string_view data = R"( +let b : B, b = true; +b; +)"; + + string_input input{data, "test.pgs"}; + auto root_node = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*root_node}; + ASTNodeDataTypeBuilder{*root_node}; + + REQUIRE(root_node->children[1]->is_type<language::name>()); + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list; + ASTNodeDataTypeFlattener{*root_node->children[1], flattened_datatype_list}; + + REQUIRE(flattened_datatype_list.size() == 1); + REQUIRE(flattened_datatype_list[0].m_data_type == ASTNodeDataType::bool_t); + REQUIRE(&flattened_datatype_list[0].m_parent_node == root_node->children[1].get()); + } + + SECTION("N") + { + std::string_view data = R"( +let n : N; +n; +)"; + + string_input input{data, "test.pgs"}; + auto root_node = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*root_node}; + ASTNodeDataTypeBuilder{*root_node}; + + REQUIRE(root_node->children[1]->is_type<language::name>()); + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list; + ASTNodeDataTypeFlattener{*root_node->children[1], flattened_datatype_list}; + + REQUIRE(flattened_datatype_list.size() == 1); + REQUIRE(flattened_datatype_list[0].m_data_type == ASTNodeDataType::unsigned_int_t); + REQUIRE(&flattened_datatype_list[0].m_parent_node == root_node->children[1].get()); + } + } + + SECTION("Compound types") + { + SECTION("function evaluation -> N") + { + std::string_view data = R"( +let f: N -> N, n -> n; +f(2); +)"; + + string_input input{data, "test.pgs"}; + auto root_node = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*root_node}; + ASTNodeDataTypeBuilder{*root_node}; + + // optimizations + ASTNodeDeclarationToAffectationConverter{*root_node}; + + ASTNodeTypeCleaner<language::var_declaration>{*root_node}; + ASTNodeTypeCleaner<language::fct_declaration>{*root_node}; + + REQUIRE(root_node->children[0]->is_type<language::function_evaluation>()); + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list; + ASTNodeDataTypeFlattener{*root_node->children[0], flattened_datatype_list}; + + REQUIRE(flattened_datatype_list.size() == 1); + REQUIRE(flattened_datatype_list[0].m_data_type == ASTNodeDataType::unsigned_int_t); + REQUIRE(&flattened_datatype_list[0].m_parent_node == root_node->children[0].get()); + } + + SECTION("function evaluation -> N*R*B*string*Z") + { + std::string_view data = R"( +let f: N -> N*R*B*string*Z, n -> (n, 0.5*n, n>2, n, 3-n); +f(2); +)"; + + string_input input{data, "test.pgs"}; + auto root_node = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*root_node}; + ASTNodeDataTypeBuilder{*root_node}; + + // optimizations + ASTNodeDeclarationToAffectationConverter{*root_node}; + + ASTNodeTypeCleaner<language::var_declaration>{*root_node}; + ASTNodeTypeCleaner<language::fct_declaration>{*root_node}; + + REQUIRE(root_node->children[0]->is_type<language::function_evaluation>()); + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list; + ASTNodeDataTypeFlattener{*root_node->children[0], flattened_datatype_list}; + + REQUIRE(flattened_datatype_list.size() == 5); + REQUIRE(flattened_datatype_list[0].m_data_type == ASTNodeDataType::unsigned_int_t); + REQUIRE(flattened_datatype_list[1].m_data_type == ASTNodeDataType::double_t); + REQUIRE(flattened_datatype_list[2].m_data_type == ASTNodeDataType::bool_t); + REQUIRE(flattened_datatype_list[3].m_data_type == ASTNodeDataType::string_t); + REQUIRE(flattened_datatype_list[4].m_data_type == ASTNodeDataType::int_t); + } + + SECTION("function evaluation -> R*R^3") + { + std::string_view data = R"( +let f: R -> R*R^3, x -> (0.5*x, (x, x+1, x-1)); +f(2); +)"; + + string_input input{data, "test.pgs"}; + auto root_node = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*root_node}; + ASTNodeDataTypeBuilder{*root_node}; + + // optimizations + ASTNodeDeclarationToAffectationConverter{*root_node}; + + ASTNodeTypeCleaner<language::var_declaration>{*root_node}; + ASTNodeTypeCleaner<language::fct_declaration>{*root_node}; + + REQUIRE(root_node->children[0]->is_type<language::function_evaluation>()); + + ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list; + ASTNodeDataTypeFlattener{*root_node->children[0], flattened_datatype_list}; + + REQUIRE(flattened_datatype_list.size() == 2); + REQUIRE(flattened_datatype_list[0].m_data_type == ASTNodeDataType::double_t); + REQUIRE(flattened_datatype_list[1].m_data_type == ASTNodeDataType::vector_t); + REQUIRE(flattened_datatype_list[1].m_data_type.dimension() == 3); + } + } +} diff --git a/tests/test_ASTNodeDeclarationToAffectationConverter.cpp b/tests/test_ASTNodeDeclarationToAffectationConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e9912e1a43d94bef7bb7e707991b9a855d111ed --- /dev/null +++ b/tests/test_ASTNodeDeclarationToAffectationConverter.cpp @@ -0,0 +1,109 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::none}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeDeclarationToAffectationConverter", "[language]") +{ + SECTION("nothing to convert") + { + std::string_view data = R"( +let z:R; +)"; + + std::string_view result = R"( +(root) + `-(language::var_declaration) + +-(language::name:z) + `-(language::R_set) +)"; + + CHECK_AST(data, result); + } + + SECTION("simple constructor") + { + std::string_view data = R"( +let z :R, z = 0; +)"; + + std::string_view result = R"( +(root) + `-(language::eq_op) + +-(language::name:z) + `-(language::integer:0) +)"; + + CHECK_AST(data, result); + } + + SECTION("complex constructors") + { + std::string_view data = R"( +let k:N, k = 0; +for(let i:N, i=0; i<2; ++i) { + let j:N, j = 2*i+k; + k = 2*j-1; +} +)"; + + std::string_view result = R"( +(root) + +-(language::eq_op) + | +-(language::name:k) + | `-(language::integer:0) + `-(language::for_statement) + +-(language::eq_op) + | +-(language::name:i) + | `-(language::integer:0) + +-(language::lesser_op) + | +-(language::name:i) + | `-(language::integer:2) + +-(language::unary_plusplus) + | `-(language::name:i) + `-(language::for_statement_block) + +-(language::eq_op) + | +-(language::name:j) + | `-(language::plus_op) + | +-(language::multiply_op) + | | +-(language::integer:2) + | | `-(language::name:i) + | `-(language::name:k) + `-(language::eq_op) + +-(language::name:k) + `-(language::minus_op) + +-(language::multiply_op) + | +-(language::integer:2) + | `-(language::name:j) + `-(language::integer:1) +)"; + + CHECK_AST(data, result); + } +} diff --git a/tests/test_ASTNodeEmptyBlockCleaner.cpp b/tests/test_ASTNodeEmptyBlockCleaner.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a52730e662268621db4a22fa5237136ef5d053a8 --- /dev/null +++ b/tests/test_ASTNodeEmptyBlockCleaner.cpp @@ -0,0 +1,142 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeEmptyBlockCleaner.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeEmptyBlockCleaner{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeEmptyBlockCleaner", "[language]") +{ + SECTION("empty file") + { + std::string_view data = R"( +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("keep non-empty block") + { + std::string_view data = R"( +{ + let x:R, x = 3; +} +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::block:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + +-(language::name:x:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("remove empty block") + { + std::string_view data = R"( +{ + let x:R; +} +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("remove nested empty blocks") + { + std::string_view data = R"( +{ + let x:R; + { + let y :R; + } + { + let z: R; + { + let w : R; + } + } +} +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("remove nested empty blocks") + { + std::string_view data = R"( +{ + let x:R; + { + let y:R; + } + { + let z:R; + { + let w:R, w = 4; + } + } +} +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::block:ASTNodeListProcessor) + `-(language::block:ASTNodeListProcessor) + `-(language::block:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + +-(language::name:w:NameProcessor) + `-(language::integer:4:ValueProcessor) +)"; + + CHECK_AST(data, result); + } +} diff --git a/tests/test_ASTNodeExpressionBuilder.cpp b/tests/test_ASTNodeExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..801d27d01f0dd89f206d5e9902c9e9414687559f --- /dev/null +++ b/tests/test_ASTNodeExpressionBuilder.cpp @@ -0,0 +1,894 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define CHECK_AST_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeExpressionBuilder", "[language]") +{ + SECTION("empty file") + { + std::string_view data = R"( +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("values") + { + SECTION("integer") + { + std::string_view data = R"( +3; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("real") + { + std::string_view data = R"( +2.3e-5; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::real:2.3e-5:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("literal") + { + std::string_view data = R"( +"foo"; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::literal:"foo":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("true") + { + std::string_view data = R"( +true; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("false") + { + std::string_view data = R"( +false; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("block") + { + std::string_view data = R"( +{ + 1; +} +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::block:ASTNodeListProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("name") + { + std::string_view data = R"( +let i:N; +i; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("affectations") + { + SECTION("operator=") + { + std::string_view data = R"( +let i:N, i = 1; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + +-(language::name:i:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("operator*=") + { + std::string_view data = R"( +let i:N, i = 1; +i *= 3; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::multiplyeq_op:AffectationProcessor<language::multiplyeq_op, unsigned long, long>) + +-(language::name:i:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("operator/=") + { + std::string_view data = R"( +let x:R, x = 1; +x /= 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::divideeq_op:AffectationProcessor<language::divideeq_op, double, long>) + +-(language::name:x:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("operator+=") + { + std::string_view data = R"( +let i:N, i = 1; +i += 3; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::pluseq_op:AffectationProcessor<language::pluseq_op, unsigned long, long>) + +-(language::name:i:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("operator-=") + { + std::string_view data = R"( +let z:Z, z = 1; +z -= 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:z:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::minuseq_op:AffectationProcessor<language::minuseq_op, long, long>) + +-(language::name:z:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple -> R^3") + { + std::string_view data = R"( +let (t,x): R*R^3, (t,x) = (0,(1,2,3)); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:t:NameProcessor) + | `-(language::name:x:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:0:ValueProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("tuple -> R^2") + { + std::string_view data = R"( +let (t,x): R*R^2, (t,x) = (0,(1,2)); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:t:NameProcessor) + | `-(language::name:x:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:0:ValueProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("unary operators") + { + SECTION("unary minus for B") + { + std::string_view data = R"( +-true; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, bool>) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("unary minus for N") + { + std::string_view data = R"( +let n:N; +-n; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, unsigned long>) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("unary minus for Z") + { + std::string_view data = R"( +-1; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("unary minus for R") + { + std::string_view data = R"( +-1.2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + `-(language::real:1.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("unary not") + { + CHECK_AST_THROWS_WITH(R"(not 1;)", "invalid implicit conversion: Z -> B"); + } + + SECTION("pre-increment operator") + { + std::string_view data = R"( +let a:Z, a=1; +++a; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, long>) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("pre-decrement operator") + { + std::string_view data = R"( +let a:Z, a=1; +--a; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::unary_minusminus:IncDecExpressionProcessor<language::unary_minusminus, long>) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("post-increment operator") + { + std::string_view data = R"( +let a:Z, a=1; +a++; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::post_plusplus:IncDecExpressionProcessor<language::post_plusplus, long>) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("post-decrement operator") + { + std::string_view data = R"( +let a:Z, a=1; +a--; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:a:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::post_minusminus:IncDecExpressionProcessor<language::post_minusminus, long>) + `-(language::name:a:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("array subscript") + { + std::string_view data = R"( +let x: R^3, x = (1, 2, 3); +x[2]; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:x:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::subscript_expression:ArraySubscriptProcessor<TinyVector<3ul, double> >) + +-(language::name:x:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("binary operators") + { + SECTION("multiply") + { + std::string_view data = R"( +1*2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::multiply_op:BinaryExpressionProcessor<language::multiply_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("divide") + { + std::string_view data = R"( +1/2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::divide_op:BinaryExpressionProcessor<language::divide_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("plus") + { + std::string_view data = R"( +1+2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::plus_op:BinaryExpressionProcessor<language::plus_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("minus") + { + std::string_view data = R"( +1-2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::minus_op:BinaryExpressionProcessor<language::minus_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("or") + { + CHECK_AST_THROWS_WITH(R"(1 or 2;)", "invalid implicit conversion: Z -> B"); + } + + SECTION("and") + { + CHECK_AST_THROWS_WITH(R"(1 and 2;)", "invalid implicit conversion: Z -> B"); + } + + SECTION("xor") + { + CHECK_AST_THROWS_WITH(R"(1 xor 2;)", "invalid implicit conversion: Z -> B"); + } + + SECTION("lesser") + { + std::string_view data = R"( +1 < 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("lesser or equal") + { + std::string_view data = R"( +1 <= 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::lesser_or_eq_op:BinaryExpressionProcessor<language::lesser_or_eq_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("greater") + { + std::string_view data = R"( +1 > 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_op:BinaryExpressionProcessor<language::greater_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("greater or equal") + { + std::string_view data = R"( +1 >= 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::greater_or_eq_op:BinaryExpressionProcessor<language::greater_or_eq_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("equal") + { + std::string_view data = R"( +1 == 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::eqeq_op:BinaryExpressionProcessor<language::eqeq_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("different") + { + std::string_view data = R"( +1 != 2; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::not_eq_op:BinaryExpressionProcessor<language::not_eq_op, long, long>) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("ostream objects") + { + SECTION("cout") + { + std::string_view data = R"( +cout; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::cout_kw:OStreamProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("cerr") + { + std::string_view data = R"( +cerr; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::cerr_kw:OStreamProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("clog") + { + std::string_view data = R"( +clog; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::clog_kw:OStreamProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("statements") + { + SECTION("if") + { + std::string_view data = R"( +if(true); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::if_statement:IfProcessor) + +-(language::true_kw:ValueProcessor) + `-(language::statement_block:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("do while") + { + std::string_view data = R"( +do; while(true); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::do_while_statement:DoWhileProcessor) + +-(language::statement_block:ASTNodeListProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("while") + { + std::string_view data = R"( +while(true); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::while_statement:WhileProcessor) + +-(language::true_kw:ValueProcessor) + `-(language::statement_block:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("for") + { + SECTION("for_statement") + { + std::string_view data = R"( +for(let i:N, i=0; i<10; ++i); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::for_statement:ForProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + +-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:10:ValueProcessor) + +-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, unsigned long>) + | `-(language::name:i:NameProcessor) + `-(language::for_statement_block:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("no init") + { + std::string_view data = R"( +let i:N, i=0; +for(; i<10; ++i); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::for_statement:ForProcessor) + +-(language::for_init:FakeProcessor) + +-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:10:ValueProcessor) + +-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, unsigned long>) + | `-(language::name:i:NameProcessor) + `-(language::for_statement_block:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("no test") + { + std::string_view data = R"( +for(let i:N, i=0; ; ++i); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::for_statement:ForProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + +-(language::for_test:ValueProcessor) + +-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, unsigned long>) + | `-(language::name:i:NameProcessor) + `-(language::for_statement_block:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("no post instruction") + { + std::string_view data = R"( +for(let i:N, i=0; i<10;); +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::for_statement:ForProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + +-(language::lesser_op:BinaryExpressionProcessor<language::lesser_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:10:ValueProcessor) + +-(language::for_post:FakeProcessor) + `-(language::for_statement_block:ASTNodeListProcessor) +)"; + + CHECK_AST(data, result); + } + } + } + + SECTION("jumps instruction") + { + SECTION("break") + { + std::string_view data = R"( +break; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::break_kw:BreakProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("continue") + { + std::string_view data = R"( +continue; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + `-(language::continue_kw:ContinueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("unexpected node type") + { + std::string_view data = R"( +1; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + // One is sure that language::ignored is not treated so its a good candidate + // for this test + ast->children[0]->set_type<language::ignored>(); + REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, parse_error); + } +} diff --git a/tests/test_ASTNodeFunctionEvaluationExpressionBuilder.cpp b/tests/test_ASTNodeFunctionEvaluationExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ecb9ee4de55d752151e33f922a50262e1a2eb7c --- /dev/null +++ b/tests/test_ASTNodeFunctionEvaluationExpressionBuilder.cpp @@ -0,0 +1,78 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeFunctionEvaluationExpressionBuilder", "[language]") +{ + SECTION("C function evaluation") + { + std::string_view data = R"( +import math; +sin(3); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:BuiltinFunctionProcessor) + +-(language::name:sin:NameProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("function evaluation") + { + std::string_view data = R"( +let sum : R*R -> R, (x,y) -> x+y; +sum(1,2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:sum:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } +} diff --git a/tests/test_ASTNodeFunctionExpressionBuilder.cpp b/tests/test_ASTNodeFunctionExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e892c86367a3984cab7cb93a4d27631cda52d28 --- /dev/null +++ b/tests/test_ASTNodeFunctionExpressionBuilder.cpp @@ -0,0 +1,833 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define CHECK_AST_THROWS(data) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, parse_error); \ + } + +#define CHECK_AST_THROWS_WITH(data, error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(error)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeFunctionExpressionBuilder", "[language]") +{ + SECTION("return a B") + { + SECTION("B argument") + { + SECTION("B parameter") + { + std::string_view data = R"( +let not_v : B -> B, a -> not a; +not_v(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:not_v:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("N argument") + { + std::string_view data = R"( +let test : N -> B, n -> n<10; +test(2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:test:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z argument") + { + std::string_view data = R"( +let test : Z -> B, z -> z>3; +test(2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:test:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R argument") + { + std::string_view data = R"( +let test : R -> B, x -> x>2.3; +test(2.1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:test:NameProcessor) + `-(language::real:2.1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("return a N") + { + SECTION("N argument") + { + std::string_view data = R"( +let test : N -> N, n -> n+2; +test(2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:test:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z argument") + { + std::string_view data = R"( +let absolute : Z -> N, z -> (z>0)*z -(z<=0)*z; +absolute(-2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:absolute:NameProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("return a Z") + { + SECTION("N argument") + { + std::string_view data = R"( +let minus : N -> Z, n -> -n; +minus(true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:minus:NameProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z argument") + { + std::string_view data = R"( +let times_2 : Z -> Z, z -> z*2; +times_2(-2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:times_2:NameProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("return a string") + { + SECTION("string argument") + { + std::string_view data = R"( +let cat : string*string -> string, (s1,s2) -> s1+s2; +cat("foo", "bar"); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:cat:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("B argument conversion") + { + std::string_view data = R"( +let cat : string*string -> string, (s1,s2) -> s1+s2; +cat("foo", true); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:cat:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::true_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N argument conversion") + { + std::string_view data = R"( +let cat : string*string -> string, (s1,s2) -> s1+s2; +let n : N, n = 2; +cat("foo", n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:cat:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z argument conversion") + { + std::string_view data = R"( +let cat : string*string -> string, (s1,s2) -> s1+s2; +cat("foo", -1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:cat:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R argument conversion") + { + std::string_view data = R"( +let cat : string*string -> string, (s1,s2) -> s1+s2; +cat("foo", 2.5e-3); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:cat:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::real:2.5e-3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return R^1 -> R^1") + { + std::string_view data = R"( +let f : R^1 -> R^1, x -> x+x; +let x : R^1, x = 1; +f(x); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return R^2 -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> x+x; +let x : R^2, x = (1,2); +f(x); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return R^3 -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R^3, x -> x+x; +let x : R^3, x = (1,2,3); +f(x); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return scalar -> R^1") + { + std::string_view data = R"( +let f : R -> R^1, x -> x+1; +f(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return tuple -> R^2") + { + std::string_view data = R"( +let f : R*R -> R^2, (x,y) -> (x,y); +f(1,2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:TupleToTinyVectorProcessor<FunctionProcessor, 2ul>) + +-(language::name:f:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return tuple -> R^3") + { + std::string_view data = R"( +let f : R*R*R -> R^3, (x,y,z) -> (x,y,z); +f(1,2,3); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:TupleToTinyVectorProcessor<FunctionProcessor, 3ul>) + +-(language::name:f:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return '0' -> R^1") + { + std::string_view data = R"( +let f : R -> R^1, x -> 0; +f(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionExpressionProcessor<TinyVector<1ul, double>, ZeroType>) + +-(language::name:f:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return '0' -> R^2") + { + std::string_view data = R"( +let f : R -> R^2, x -> 0; +f(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionExpressionProcessor<TinyVector<2ul, double>, ZeroType>) + +-(language::name:f:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return '0' -> R^3") + { + std::string_view data = R"( +let f : R -> R^3, x -> 0; +f(1); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionExpressionProcessor<TinyVector<3ul, double>, ZeroType>) + +-(language::name:f:NameProcessor) + `-(language::integer:1:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return embedded R^d compound") + { + std::string_view data = R"( +let f : R*R*R*R -> R*R^1*R^2*R^3, (x,y,z,t) -> (t, (x), (x,y), (x,y,z)); +f(1,2,3,4); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + +-(language::integer:3:ValueProcessor) + `-(language::integer:4:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Return embedded R^d compound with '0'") + { + std::string_view data = R"( +let f : R*R*R*R -> R*R^1*R^2*R^3, (x,y,z,t) -> (t, 0, 0, (x,y,z)); +f(1,2,3,4); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + +-(language::integer:3:ValueProcessor) + `-(language::integer:4:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Arguments '0' -> R^1") + { + std::string_view data = R"( +let f : R^1 -> R^1, x -> x; +f(0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Arguments '0' -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> x; +f(0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Arguments '0' -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R^3, x -> x; +f(0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Arguments tuple -> R^d") + { + std::string_view data = R"( +let f: R^3 -> R, x -> x[0]+x[1]+x[2]; +f((1,2,3)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::integer:1:ValueProcessor) + +-(language::integer:2:ValueProcessor) + `-(language::integer:3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Arguments compound with tuple") + { + std::string_view data = R"( +let f: R*R^3*R^2->R, (t,x,y) -> t*(x[0]+x[1]+x[2])*y[0]+y[1]; +f(2,(1,2,3),(2,1.3)); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::function_argument_list:ASTNodeExpressionListProcessor) + +-(language::integer:2:ValueProcessor) + +-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>) + +-(language::integer:2:ValueProcessor) + `-(language::real:1.3:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("errors") + { + SECTION("wrong argument number") + { + std::string_view data = R"( +let Id : Z -> Z, z -> z; +Id(2,3); +)"; + + CHECK_AST_THROWS(data); + } + + SECTION("wrong argument number 2") + { + std::string_view data = R"( +let sum : R*R -> R, (x,y) -> x+y; +sum(2); +)"; + + CHECK_AST_THROWS(data); + } + + SECTION("invalid return implicit conversion") + { + SECTION("string -> R") + { + std::string_view data = R"( +let bad_conv : string -> R, s -> s; +bad_conv(2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R"}); + } + + SECTION("R -> B") + { + std::string_view data = R"( +let bad_B : R -> B, x -> x; +bad_B(2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> B"}); + } + + SECTION("R -> N") + { + std::string_view data = R"( +let next : R -> N, x -> x; +next(6); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> N"}); + } + + SECTION("R -> Z") + { + std::string_view data = R"( +let prev : R -> Z, x -> x; +prev(-3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); + } + + SECTION("N -> B") + { + std::string_view data = R"( +let bad_B : N -> B, n -> n; +bad_B(3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> B"}); + } + + SECTION("Z -> B") + { + std::string_view data = R"( +let bad_B : Z -> B, n -> n; +bad_B(3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> B"}); + } + } + + SECTION("invalid argument implicit conversion") + { + SECTION("N -> B") + { + std::string_view data = R"( +let negate : B -> B, b -> not b; +let n : N, n = 2; +negate(n); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> B"}); + } + + SECTION("Z -> B") + { + std::string_view data = R"( +let negate : B -> B, b -> not b; +negate(3-4); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> B"}); + } + + SECTION("R -> B") + { + std::string_view data = R"( +let negate : B -> B, b -> not b; +negate(3.24); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> B"}); + } + + SECTION("R -> N") + { + std::string_view data = R"( +let next : N -> N, n -> n+1; +next(3.24); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> N"}); + } + + SECTION("R -> Z") + { + std::string_view data = R"( +let prev : Z -> Z, z -> z-1; +prev(3 + .24); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); + } + } + + SECTION("arguments invalid tuple -> R^d conversion") + { + SECTION("tuple[3] -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R, x->x[0]; +f((1,2,3)); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + } + + SECTION("tuple[2] -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R, x->x[0]; +f((1,2)); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + } + + SECTION("compound tuple[3] -> R^2") + { + std::string_view data = R"( +let f : R*R^2 -> R, (t,x)->x[0]; +f(1,(1,2,3)); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + } + + SECTION("compound tuple[2] -> R^3") + { + std::string_view data = R"( +let f : R^3*R^2 -> R, (x,y)->x[0]*y[1]; +f((1,2),(3,4)); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + } + + SECTION("list instead of tuple -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R, x -> x[0]*x[1]; +f(1,2,3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"bad number of arguments: expecting 1, provided 3"}); + } + + SECTION("list instead of tuple -> R^3*R^2") + { + std::string_view data = R"( +let f : R^3*R^2 -> R, (x,y) -> x[0]*x[1]-y[0]; +f((1,2,3),2,3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"bad number of arguments: expecting 2, provided 3"}); + } + } + } +} diff --git a/tests/test_ASTNodeIncDecExpressionBuilder.cpp b/tests/test_ASTNodeIncDecExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60ce2489fd8b1b93996cd2904b8bf9852b8a1c79 --- /dev/null +++ b/tests/test_ASTNodeIncDecExpressionBuilder.cpp @@ -0,0 +1,467 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeIncDecExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define DISALLOWED_CHAINED_AST(data, expected_error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_error); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeIncDecExpressionBuilder", "[language]") +{ + SECTION("Pre-increment") + { + SECTION("N") + { + std::string_view data = R"( +let i : N, i=0; +++i; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, unsigned long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let i : Z, i=0; +++i; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +let x : R, x=0; +++x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, double>) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Pre-decrement") + { + SECTION("N") + { + std::string_view data = R"( +let i : N, i=1; +--i; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::unary_minusminus:IncDecExpressionProcessor<language::unary_minusminus, unsigned long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let i : Z, i=0; +--i; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::unary_minusminus:IncDecExpressionProcessor<language::unary_minusminus, long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +let x : R, x=2.3; +--x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, double>) + | +-(language::name:x:NameProcessor) + | `-(language::real:2.3:ValueProcessor) + `-(language::unary_minusminus:IncDecExpressionProcessor<language::unary_minusminus, double>) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Post-increment") + { + SECTION("N") + { + std::string_view data = R"( +let i : N, i=0; +i++; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::post_plusplus:IncDecExpressionProcessor<language::post_plusplus, unsigned long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let i : Z, i=0; +i++; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::post_plusplus:IncDecExpressionProcessor<language::post_plusplus, long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +let x : R, x=0; +x++; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, long>) + | +-(language::name:x:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::post_plusplus:IncDecExpressionProcessor<language::post_plusplus, double>) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Post-decrement") + { + SECTION("N") + { + std::string_view data = R"( +let i : N, i=1; +i--; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::post_minusminus:IncDecExpressionProcessor<language::post_minusminus, unsigned long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let i : Z, i=0; +i--; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, long, long>) + | +-(language::name:i:NameProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::post_minusminus:IncDecExpressionProcessor<language::post_minusminus, long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +let x : R, x=2.3; +x--; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, double, double>) + | +-(language::name:x:NameProcessor) + | `-(language::real:2.3:ValueProcessor) + `-(language::post_minusminus:IncDecExpressionProcessor<language::post_minusminus, double>) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Errors") + { + SECTION("Invalid operator type") + { + auto ast = std::make_unique<ASTNode>(); + REQUIRE_THROWS_WITH(ASTNodeIncDecExpressionBuilder{*ast}, + "unexpected error: undefined increment/decrement operator"); + } + + SECTION("Invalid operand type") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::unary_plusplus>(); + ast->m_data_type = ASTNodeDataType::undefined_t; + + ast->children.emplace_back(std::make_unique<ASTNode>()); + + REQUIRE_THROWS_WITH(ASTNodeIncDecExpressionBuilder{*ast}, "invalid operand type for unary operator"); + } + + SECTION("Invalid data type") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::unary_plusplus>(); + + ast->children.emplace_back(std::make_unique<ASTNode>()); + ast->children[0]->set_type<language::name>(); + + REQUIRE_THROWS_WITH(ASTNodeIncDecExpressionBuilder{*ast}, + "unexpected error: undefined data type for unary operator"); + } + + SECTION("Not allowed chained ++/--") + { + SECTION("++ ++ a") + { + std::string_view data = R"( +1 ++ ++; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("++ -- a") + { + std::string_view data = R"( +1 ++ --; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("-- ++ a") + { + std::string_view data = R"( +1 -- ++; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("-- -- a") + { + std::string_view data = R"( +1 -- --; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("a ++ ++") + { + std::string_view data = R"( +++ ++ 1; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("a ++ --") + { + std::string_view data = R"( +++ -- 1; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("a -- ++") + { + std::string_view data = R"( +-- ++ 1; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("a -- --") + { + std::string_view data = R"( +-- -- 1; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("++ a ++") + { + std::string_view data = R"( +++ 1 ++; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("++ a --") + { + std::string_view data = R"( +++ 1 --; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("-- a ++") + { + std::string_view data = R"( +-- 1 ++; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + + SECTION("-- --") + { + std::string_view data = R"( +-- 1 --; +)"; + + std::string error_message = R"(chaining ++ or -- operators is not allowed)"; + + DISALLOWED_CHAINED_AST(data, error_message) + } + } + } +} diff --git a/tests/test_ASTNodeJumpPlacementChecker.cpp b/tests/test_ASTNodeJumpPlacementChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..419519cd5803473aadb56abea772d537aaf38c2a --- /dev/null +++ b/tests/test_ASTNodeJumpPlacementChecker.cpp @@ -0,0 +1,151 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeJumpPlacementChecker.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeJumpPlacementChecker", "[language]") +{ + SECTION("break") + { + SECTION("in for loop") + { + std::string_view data = R"( +for(;;) { + break; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast}); + } + + SECTION("in while loop") + { + std::string_view data = R"( +while(true) { + break; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast}); + } + + SECTION("in do while loop") + { + std::string_view data = R"( +do { + break; +} while(true); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast}); + } + + SECTION("misplaced") + { + std::string_view data = R"( +{ + break; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ast->children[0]->m_data_type = ASTNodeDataType::undefined_t; + + REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, parse_error); + } + } + + SECTION("continue") + { + SECTION("in for loop") + { + std::string_view data = R"( +for(;;) { + continue; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast}); + } + + SECTION("in while loop") + { + std::string_view data = R"( +while(true) { + continue; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast}); + } + + SECTION("in do while loop") + { + std::string_view data = R"( +do { + continue; +} while(true); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast}); + } + + SECTION("misplaced") + { + std::string_view data = R"( +{ + continue; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ast->children[0]->m_data_type = ASTNodeDataType::undefined_t; + + REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, parse_error); + } + } +} diff --git a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..333b98bd998124e676c885025ef1d646ba517829 --- /dev/null +++ b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp @@ -0,0 +1,400 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeListAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define CHECK_AST_THROWS_WITH(data, error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(error)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeListAffectationExpressionBuilder", "[language]") +{ + const std::string demangled_stdstring = demangle(typeid(std::string{}).name()); + + SECTION("Declaration") + { + SECTION("without conversion R*R") + { + std::string_view data = R"( +let (x, y) : R*R, (x,y) = (2.3, 6.2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:x:NameProcessor) + | `-(language::name:y:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:2.3:ValueProcessor) + `-(language::real:6.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("without conversion B*Z*N") + { + std::string_view data = R"( +let n:N, n = 2; +let ( b, z , m ): B*Z*N, (b,z,m) = (false, -2, n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:z:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::false_kw:ValueProcessor) + +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + | `-(language::integer:2:ValueProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("with conversion R*B*Z*N") + { + std::string_view data = R"( +let (r,b,z,m) : R*B*Z*N, (r,b,z,m) = (3.2, true, 6, 2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:z:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:3.2:ValueProcessor) + +-(language::true_kw:ValueProcessor) + +-(language::integer:6:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("with conversion R*R*R*R") + { + std::string_view data = R"( +let (r,b,z,m): R*R*R*R , (r,b,z,m) = (3.2, 1, 6, 2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:z:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:3.2:ValueProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:6:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("without conversion R^1*R^2*R^3*R") + { + std::string_view data = R"( +let a:R^1, a = 0; +let b:R^2, b = (1,2); +let c:R^3, c = (1,2,3); +let (x1,x2,x3,x) : R^1*R^2*R^3*R, + (x1,x2,x3,x) = (a, b, c, 2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationFromZeroProcessor<TinyVector<1ul, double> >) + | +-(language::name:a:NameProcessor) + | `-(language::integer:0:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) + | +-(language::name:b:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | `-(language::integer:2:ValueProcessor) + +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) + | +-(language::name:c:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:x1:NameProcessor) + | +-(language::name:x2:NameProcessor) + | +-(language::name:x3:NameProcessor) + | `-(language::name:x:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::name:a:NameProcessor) + +-(language::name:b:NameProcessor) + +-(language::name:c:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Zero initialization") + { + std::string_view data = R"( +let (x1,x2,x3,x) : R^1*R^2*R^3*R, (x1,x2,x3,x) = (0, 0, 0, 0); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:x1:NameProcessor) + | +-(language::name:x2:NameProcessor) + | +-(language::name:x3:NameProcessor) + | `-(language::name:x:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::integer:0:ValueProcessor) + +-(language::integer:0:ValueProcessor) + +-(language::integer:0:ValueProcessor) + `-(language::integer:0:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from function") + { + std::string_view data = R"( +let f: R -> R*R, x -> (x*x, x+1); +let (x,y): R*R, (x,y) = f(2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:x:NameProcessor) + | `-(language::name:y:NameProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string without conversion") + { + std::string_view data = R"( +let (s,r): string*string, (s,r) = ("foo","bar"); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:s:NameProcessor) + | `-(language::name:r:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string with conversion") + { + std::string_view data = R"( +let n:N, n =2; +let (r,s,t,u) : string*string*string*string, + (r,s,t,u) = (3.2, -2, true, n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:s:NameProcessor) + | +-(language::name:t:NameProcessor) + | `-(language::name:u:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:3.2:ValueProcessor) + +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + | `-(language::integer:2:ValueProcessor) + +-(language::true_kw:ValueProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Errors") + { + SECTION("invalid affectation rhs") + { + std::string_view data = R"( +let x:R; +let i:R; +(x,i) = 3; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid right hand side in tuple affectation"}); + } + + SECTION("incompatible list sizes") + { + std::string_view data = R"( +let (x,y) : R*R, (x,y) = (3, 3, 2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes 2") + { + std::string_view data = R"( +let (x,y,z):R*R*R, (x,y,z) = (1, 2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes from function evaluation") + { + std::string_view data = R"( +let f: R -> R, x -> x*x; +let(x,y) : R*R, (x,y) = f(3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes from function evaluation") + { + std::string_view data = R"( +let(x,y):R*R,(x,y)=(2,3); +(x,y) += (1,4); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation operator for tuples"}); + } + + SECTION("invalid operand type for affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +let (x,y) : R*R, (x,y) = (f,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> R"}); + } + + SECTION("invalid operand type for string affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +let (s,n):string*N, (s,n) = (f,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> string"}); + } + + SECTION("invalid value type for affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +let x:R; + +(f,x) = (3,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> function"}); + } + + SECTION("invalid R^n -> R^m conversion") + { + std::string_view data = R"( +let x:R^2, x = (1,2); +let y:R^3, y = x; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + } + + SECTION("invalid Z -> R^d conversion (non-zero)") + { + std::string_view data = R"( +let x:R^2, x = 1; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^2"}); + } + } +} diff --git a/tests/test_ASTNodeListProcessor.cpp b/tests/test_ASTNodeListProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bccd0080fb1de962815aef8f95d95f1e02a5fef3 --- /dev/null +++ b/tests/test_ASTNodeListProcessor.cpp @@ -0,0 +1,44 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/node_processor/ASTNodeListProcessor.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeListProcessor", "[language]") +{ + rang::setControlMode(rang::control::Off); + + std::string_view data = R"( +3; +true; +2.3; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeDeclarationToAffectationConverter{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + + ASTNodeExpressionBuilder{*ast}; + ExecutionPolicy exec_policy; + ast->execute(exec_policy); + + REQUIRE(ast->children[0]->is_type<language::integer>()); + REQUIRE(ast->children[1]->is_type<language::true_kw>()); + REQUIRE(ast->children[2]->is_type<language::real>()); + + REQUIRE(ast->m_node_processor->typeIdName() == demangle<ASTNodeListProcessor>()); +} diff --git a/tests/test_ASTNodeNaturalConversionChecker.cpp b/tests/test_ASTNodeNaturalConversionChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe29cf9d0148d7a4d0a31bd71b97d84820e63299 --- /dev/null +++ b/tests/test_ASTNodeNaturalConversionChecker.cpp @@ -0,0 +1,1512 @@ +#include <catch2/catch.hpp> + +#include <language/PEGGrammar.hpp> +#include <language/ast/ASTNode.hpp> +#include <language/ast/ASTNodeNaturalConversionChecker.hpp> + +namespace language +{ +struct integer; +} + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeNaturalConversionChecker", "[language]") +{ + SECTION("Valid conversions") + { + std::unique_ptr data_node = std::make_unique<ASTNode>(); + + SECTION("-> string") + { + SECTION("string -> string") + { + data_node->m_data_type = ASTNodeDataType::string_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + + SECTION("R^d -> string") + { + data_node->m_data_type = ASTNodeDataType::vector_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + + SECTION("R -> string") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + + SECTION("Z -> string") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + + SECTION("N -> string") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + + SECTION("B -> string") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + + SECTION("list -> string") + { + data_node->m_data_type = ASTNodeDataType::list_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + + SECTION("tuple -> string") + { + data_node->m_data_type = ASTNodeDataType::tuple_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t}); + } + } + + SECTION("-> R^d") + { + SECTION("R^1 -> R^1") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 1}}); + } + + SECTION("list -> R^1") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + } + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 1}}); + } + + SECTION("'0' -> R^d") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::int_t, 1}; + data_node->set_type<language::integer>(); + data_node->source = "0"; + auto& source = data_node->source; + data_node->m_begin = TAO_PEGTL_NAMESPACE::internal::iterator{&source[0]}; + data_node->m_end = TAO_PEGTL_NAMESPACE::internal::iterator{&source[source.size()]}; + + SECTION("d = 1") + { + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 1}}); + } + SECTION("d = 2") + { + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 2}}); + } + SECTION("d = 3") + { + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 3}}); + } + } + + SECTION("R^2 -> R^2") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 2}}); + } + + SECTION("list -> R^2") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + } + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 2}}); + } + + SECTION("R^3 -> R^3") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 3}}); + } + + SECTION("list -> R^3") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::int_t; + data_node->emplace_back(std::move(list2_node)); + } + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 3}}); + } + } + + SECTION("-> R") + { + SECTION("R -> R") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}); + } + + SECTION("Z -> R") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}); + } + + SECTION("N -> R") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}); + } + + SECTION("B -> R") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}); + } + } + + SECTION("-> Z") + { + SECTION("Z -> Z") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}); + } + + SECTION("N -> Z") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}); + } + + SECTION("B -> Z") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}); + } + } + + SECTION("-> N") + { + SECTION("Z -> N") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}); + } + + SECTION("N -> N") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}); + } + + SECTION("B -> N") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}); + } + } + + SECTION("-> B") + { + SECTION("B -> B") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}); + } + } + + SECTION("-> tuple") + { + SECTION("B -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::bool_t}}}); + } + + SECTION("B -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}}); + } + + SECTION("N -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}}); + } + + SECTION("Z -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}}); + } + + SECTION("B -> tuple(Z)") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::int_t}}}); + } + + SECTION("N -> tuple(Z)") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::int_t}}}); + } + + SECTION("Z -> tuple(Z)") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::int_t}}}); + } + + SECTION("B -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::double_t}}}); + } + + SECTION("N -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::double_t}}}); + } + + SECTION("Z -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::double_t}}}); + } + + SECTION("R -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::double_t}}}); + } + + SECTION("R^1 -> tuple(R^1)") + { + auto R1 = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + data_node->m_data_type = R1; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R1}}); + } + + SECTION("R^2 -> tuple(R^2)") + { + auto R2 = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + data_node->m_data_type = R2; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}); + } + + SECTION("R^3 -> tuple(R^3)") + { + auto R3 = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + data_node->m_data_type = R3; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R3}}); + } + + SECTION("string -> tuple(string)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::string_t}; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ASTNodeDataType::string_t}}}); + } + + SECTION("type_id_t -> tuple(type_id_t)") + { + auto type_id = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}; + data_node->m_data_type = type_id; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, type_id}}); + } + + SECTION("(B, B, B) -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::bool_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::bool_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::bool_t; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(B, N, Z) -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::bool_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::int_t; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(B, N, Z) -> tuple(Z)") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::bool_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::int_t; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(R, N, Z) -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::int_t; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(R^1, R^1) -> tuple(R^1)") + { + auto R1 = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = R1; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = R1; + data_node->emplace_back(std::move(list1_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R1}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(R^2, R^2, R^2) -> tuple(R^2)") + { + auto R2 = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = R2; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = R2; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = R2; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R2}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(R^3, R^3) -> tuple(R^3)") + { + auto R3 = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = R3; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = R3; + data_node->emplace_back(std::move(list1_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R3}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(string, string) -> tuple(string)") + { + auto str_t = ASTNodeDataType{ASTNodeDataType::string_t}; + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = str_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = str_t; + data_node->emplace_back(std::move(list1_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, str_t}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("(type_id_t, type_id_t) -> tuple(type_id_t)") + { + auto type_id = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}; + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = type_id; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = type_id; + data_node->emplace_back(std::move(list1_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(B) -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(B) -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(Z) -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(N) -> tuple(N)") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(B) -> tuple(Z)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(N) -> tuple(Z)") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(Z) -> tuple(Z)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(B) -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(Z) -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(N) -> tuple(R)") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(R) -> tuple(R)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(B) -> tuple(string)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(Z) -> tuple(string)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(N) -> tuple(string)") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(R) -> tuple(string)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(string) -> tuple(string)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}}; + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}}; + + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t}); + } + + SECTION("tuple(R^1) -> tuple(R^1)") + { + auto R1 = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, R1}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R1}}); + } + + SECTION("tuple(R^2) -> tuple(R^2)") + { + auto R2 = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, R2}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}); + } + + SECTION("tuple(R^3) -> tuple(R^3)") + { + auto R3 = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, R3}; + REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R3}}); + } + + SECTION("tuple(type_id_t) -> tuple(type_id_t)") + { + auto type_id = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}; + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id}; + REQUIRE_NOTHROW( + ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, type_id}}); + } + } + } + + SECTION("Invalid conversions") + { + std::unique_ptr data_node = std::make_unique<ASTNode>(); + + SECTION("-> R^d") + { + SECTION("R^2 -> R^1") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "incompatible dimensions in affectation"); + } + + SECTION("R^3 -> R^1") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "incompatible dimensions in affectation"); + } + + SECTION("R^1 -> R^2") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "incompatible dimensions in affectation"); + } + + SECTION("R^3 -> R^2") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "incompatible dimensions in affectation"); + } + + SECTION("R^1 -> R^3") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "incompatible dimensions in affectation"); + } + + SECTION("R^2 -> R^3") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "incompatible dimensions in affectation"); + } + + SECTION("list1 -> R^d") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + } + + SECTION("d=2") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "incompatible dimensions in affectation"); + } + + SECTION("d=3") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "incompatible dimensions in affectation"); + } + } + + SECTION("list2 -> R^d") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + } + + SECTION("d=1") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "incompatible dimensions in affectation"); + } + + SECTION("d=3") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "incompatible dimensions in affectation"); + } + } + + SECTION("list3 -> R^d") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::int_t; + data_node->emplace_back(std::move(list2_node)); + } + + SECTION("d=1") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "incompatible dimensions in affectation"); + } + + SECTION("d=2") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "incompatible dimensions in affectation"); + } + } + + SECTION("tuple -> R^d") + { + SECTION("tuple(N) -> R^1") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "invalid implicit conversion: tuple(N) -> R^1"); + } + + SECTION("tuple(R) -> R^1") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "invalid implicit conversion: tuple(R) -> R^1"); + } + + SECTION("tuple(R) -> R^2") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "invalid implicit conversion: tuple(R) -> R^2"); + } + + SECTION("tuple(B) -> R^2") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "invalid implicit conversion: tuple(B) -> R^2"); + } + + SECTION("tuple(Z) -> R^3") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "invalid implicit conversion: tuple(Z) -> R^3"); + } + + SECTION("tuple(R) -> R^3") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "invalid implicit conversion: tuple(R) -> R^3"); + } + + SECTION("tuple(R^1) -> tuple(R^3)") + { + auto tuple_R1 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}}; + auto tuple_R3 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3}}; + data_node->m_data_type = tuple_R1; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R3}), + "invalid implicit conversion: R^1 -> R^3"); + } + + SECTION("tuple(R^2) -> tuple(R^3)") + { + auto tuple_R2 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2}}; + auto tuple_R3 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3}}; + data_node->m_data_type = tuple_R2; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R3}), + "invalid implicit conversion: R^2 -> R^3"); + } + + SECTION("tuple(R^2) -> tuple(R^1)") + { + auto tuple_R1 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}}; + auto tuple_R2 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2}}; + data_node->m_data_type = tuple_R2; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R1}), + "invalid implicit conversion: R^2 -> R^1"); + } + + SECTION("tuple(R) -> tuple(Z)") + { + auto tuple_R = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + auto tuple_Z = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + data_node->m_data_type = tuple_R; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_Z}), + "invalid implicit conversion: R -> Z"); + } + + SECTION("tuple(R) -> tuple(R^1)") + { + auto tuple_R = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + auto tuple_R1 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}}; + data_node->m_data_type = tuple_R; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R1}), + "invalid implicit conversion: R -> R^1"); + } + + SECTION("tuple(string) -> tuple(R)") + { + auto tuple_string = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}}; + auto tuple_R = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + data_node->m_data_type = tuple_string; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R}), + "invalid implicit conversion: string -> R"); + } + + SECTION("tuple(type_id) -> tuple(R)") + { + auto type_id = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}; + + auto tuple_type_id = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id}; + auto tuple_R = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + data_node->m_data_type = tuple_type_id; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R}), + "invalid implicit conversion: foo -> R"); + } + + SECTION("tuple(type_id) -> tuple(R)") + { + auto type_id0 = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}; + auto type_id1 = ASTNodeDataType{ASTNodeDataType::type_id_t, "bar"}; + + auto tuple_type_id0 = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id0}; + auto tuple_type_id1 = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id1}; + data_node->m_data_type = tuple_type_id0; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_type_id1}), + "invalid implicit conversion: foo -> bar"); + } + } + + SECTION("R -> R^d") + { + data_node->m_data_type = ASTNodeDataType::double_t; + + SECTION("d=1") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "invalid implicit conversion: R -> R^1"); + } + + SECTION("d=2") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "invalid implicit conversion: R -> R^2"); + } + + SECTION("d=3") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "invalid implicit conversion: R -> R^3"); + } + } + + SECTION("Z -> R^d (non-zero)") + { + data_node->m_data_type = ASTNodeDataType::int_t; + data_node->set_type<language::integer>(); + data_node->source = "1"; + auto& source = data_node->source; + data_node->m_begin = TAO_PEGTL_NAMESPACE::internal::iterator{&source[0]}; + data_node->m_end = TAO_PEGTL_NAMESPACE::internal::iterator{&source[source.size()]}; + + SECTION("d=1") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "invalid implicit conversion: Z -> R^1"); + } + + SECTION("d=2") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "invalid implicit conversion: Z -> R^2"); + } + + SECTION("d=3") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "invalid implicit conversion: Z -> R^3"); + } + } + + SECTION("N -> R^d") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + + SECTION("d=1") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "invalid implicit conversion: N -> R^1"); + } + + SECTION("d=2") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "invalid implicit conversion: N -> R^2"); + } + + SECTION("d=3") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "invalid implicit conversion: N -> R^3"); + } + } + + SECTION("B -> R^d") + { + data_node->m_data_type = ASTNodeDataType::bool_t; + + SECTION("d=1") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "invalid implicit conversion: B -> R^1"); + } + + SECTION("d=2") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "invalid implicit conversion: B -> R^2"); + } + + SECTION("d=3") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "invalid implicit conversion: B -> R^3"); + } + } + + SECTION("string -> R^d") + { + data_node->m_data_type = ASTNodeDataType::string_t; + + SECTION("d=1") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 1}}), + "invalid implicit conversion: string -> R^1"); + } + + SECTION("d=2") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 2}}), + "invalid implicit conversion: string -> R^2"); + } + + SECTION("d=3") + { + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::vector_t, 3}}), + "invalid implicit conversion: string -> R^3"); + } + } + } + + SECTION("-> R") + { + SECTION("string -> R") + { + data_node->m_data_type = ASTNodeDataType::string_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}), + "invalid implicit conversion: string -> R"); + } + + SECTION("R^1 -> R") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}), + "invalid implicit conversion: R^1 -> R"); + } + + SECTION("R^2 -> R") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}), + "invalid implicit conversion: R^2 -> R"); + } + + SECTION("R^3 -> R") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}), + "invalid implicit conversion: R^3 -> R"); + } + + SECTION("tuple(N) -> R") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}), + "invalid implicit conversion: tuple(N) -> R"); + } + + SECTION("tuple(R) -> R") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}), + "invalid implicit conversion: tuple(R) -> R"); + } + } + + SECTION("-> Z") + { + SECTION("string -> Z") + { + data_node->m_data_type = ASTNodeDataType::string_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}), + "invalid implicit conversion: string -> Z"); + } + + SECTION("R^1 -> Z") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}), + "invalid implicit conversion: R^1 -> Z"); + } + + SECTION("R^2 -> Z") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}), + "invalid implicit conversion: R^2 -> Z"); + } + + SECTION("R^3 -> Z") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}), + "invalid implicit conversion: R^3 -> Z"); + } + + SECTION("R -> Z") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}), + "invalid implicit conversion: R -> Z"); + } + + SECTION("tuple(N) -> Z") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}), + "invalid implicit conversion: tuple(N) -> Z"); + } + + SECTION("tuple(Z) -> Z") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}), + "invalid implicit conversion: tuple(Z) -> Z"); + } + } + + SECTION("-> N") + { + SECTION("string -> N") + { + data_node->m_data_type = ASTNodeDataType::string_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}), + "invalid implicit conversion: string -> N"); + } + + SECTION("R^1 -> N") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}), + "invalid implicit conversion: R^1 -> N"); + } + + SECTION("R^2 -> N") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}), + "invalid implicit conversion: R^2 -> N"); + } + + SECTION("R^3 -> N") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}), + "invalid implicit conversion: R^3 -> N"); + } + + SECTION("R -> N") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}), + "invalid implicit conversion: R -> N"); + } + + SECTION("tuple(Z) -> N") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}), + "invalid implicit conversion: tuple(Z) -> N"); + } + + SECTION("tuple(N) -> N") + { + data_node->m_data_type = + ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}), + "invalid implicit conversion: tuple(N) -> N"); + } + } + + SECTION("-> B") + { + SECTION("string -> B") + { + data_node->m_data_type = ASTNodeDataType::string_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: string -> B"); + } + + SECTION("R^1 -> B") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: R^1 -> B"); + } + + SECTION("R^2 -> B") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: R^2 -> B"); + } + + SECTION("R^3 -> B") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: R^3 -> B"); + } + + SECTION("R -> B") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: R -> B"); + } + + SECTION("Z -> B") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: Z -> B"); + } + + SECTION("N -> B") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: N -> B"); + } + + SECTION("tuple(Z) -> B") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: tuple(Z) -> B"); + } + + SECTION("tuple(B) -> B") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}), + "invalid implicit conversion: tuple(B) -> B"); + } + } + + SECTION("-> tuple") + { + SECTION("N -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType::unsigned_int_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::bool_t}}}), + "invalid implicit conversion: N -> B"); + } + + SECTION("Z -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType::int_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::bool_t}}}), + "invalid implicit conversion: Z -> B"); + } + + SECTION("R -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::bool_t}}}), + "invalid implicit conversion: R -> B"); + } + + SECTION("string -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType::string_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::bool_t}}}), + "invalid implicit conversion: string -> B"); + } + + SECTION("R^1 -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::bool_t}}}), + "invalid implicit conversion: R^1 -> B"); + } + + SECTION("R^2 -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::bool_t}}}), + "invalid implicit conversion: R^2 -> B"); + } + + SECTION("R^3 -> tuple(B)") + { + data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::bool_t}}}), + "invalid implicit conversion: R^3 -> B"); + } + + SECTION("R -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType::double_t; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::tuple_t, + ASTNodeDataType{ + ASTNodeDataType::unsigned_int_t}}}), + "invalid implicit conversion: R -> N"); + } + + SECTION("R^1 -> tuple(R^2)") + { + auto R1 = ASTNodeDataType{ASTNodeDataType::vector_t, 1}; + auto R2 = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + data_node->m_data_type = R1; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}), + "incompatible dimensions in affectation"); + } + + SECTION("R^2 -> tuple(R^3)") + { + auto R2 = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + auto R3 = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + data_node->m_data_type = R2; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::tuple_t, R3}}), + "incompatible dimensions in affectation"); + } + + SECTION("R^3 -> tuple(R^2)") + { + auto R3 = ASTNodeDataType{ASTNodeDataType::vector_t, 3}; + auto R2 = ASTNodeDataType{ASTNodeDataType::vector_t, 2}; + data_node->m_data_type = R3; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, + ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}), + "incompatible dimensions in affectation"); + } + + SECTION("(B, R, Z) -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::bool_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::int_t; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}), + "invalid implicit conversion: R -> N"); + } + + SECTION("(R, N, Z) -> tuple(Z)") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::int_t; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}), + "invalid implicit conversion: R -> Z"); + } + + SECTION("(B, N, R) -> tuple(N)") + { + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = ASTNodeDataType::bool_t; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = ASTNodeDataType::unsigned_int_t; + data_node->emplace_back(std::move(list1_node)); + + std::unique_ptr list2_node = std::make_unique<ASTNode>(); + list2_node->m_data_type = ASTNodeDataType::double_t; + data_node->emplace_back(std::move(list2_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}), + "invalid implicit conversion: R -> N"); + } + } + + SECTION("(type_id_t, type_id_t) -> tuple(type_id_t)") + { + auto type_id1 = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}; + auto type_id2 = ASTNodeDataType{ASTNodeDataType::type_id_t, "bar"}; + data_node->m_data_type = ASTNodeDataType::list_t; + { + std::unique_ptr list0_node = std::make_unique<ASTNode>(); + list0_node->m_data_type = type_id1; + data_node->emplace_back(std::move(list0_node)); + + std::unique_ptr list1_node = std::make_unique<ASTNode>(); + list1_node->m_data_type = type_id2; + data_node->emplace_back(std::move(list1_node)); + } + auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id2}; + REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}), + "invalid implicit conversion: foo -> bar"); + } + } +} diff --git a/tests/test_ASTNodeTypeCleaner.cpp b/tests/test_ASTNodeTypeCleaner.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80d7ccfc081a0d4cc5165a38b99ba0214975e11a --- /dev/null +++ b/tests/test_ASTNodeTypeCleaner.cpp @@ -0,0 +1,94 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::none}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeTypeCleaner", "[language]") +{ + SECTION("no declaration") + { + std::string_view data = R"( +cout << "two=" << 2 << "\n"; +)"; + + std::string_view result = R"( +(root) + `-(language::cout_kw) + +-(language::literal:"two=") + +-(language::integer:2) + `-(language::literal:"\n") +)"; + + CHECK_AST(data, result); + } + + SECTION("single declaration") + { + std::string_view data = R"( +let z:R; +z = 1; +)"; + + std::string_view result = R"( +(root) + `-(language::eq_op) + +-(language::name:z) + `-(language::integer:1) +)"; + + CHECK_AST(data, result); + } + + SECTION("multiple declaration") + { + std::string_view data = R"( +let z:Z; +z = 1; +if (true) { + let x:R; + x = 0.5 *z; +} +)"; + + std::string_view result = R"( +(root) + +-(language::eq_op) + | +-(language::name:z) + | `-(language::integer:1) + `-(language::if_statement) + +-(language::true_kw) + `-(language::block) + `-(language::eq_op) + +-(language::name:x) + `-(language::multiply_op) + +-(language::real:0.5) + `-(language::name:z) +)"; + + CHECK_AST(data, result); + } +} diff --git a/tests/test_ASTNodeUnaryOperatorExpressionBuilder.cpp b/tests/test_ASTNodeUnaryOperatorExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c30d3f0a9e8470f7156fe6aa8239002f065aee5 --- /dev/null +++ b/tests/test_ASTNodeUnaryOperatorExpressionBuilder.cpp @@ -0,0 +1,245 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTNodeUnaryOperatorExpressionBuilder.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#define CHECK_AST(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view> or \ + std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +#define CHECK_AST_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTNodeUnaryOperatorExpressionBuilder", "[language]") +{ + SECTION("unary minus") + { + SECTION("B") + { + std::string_view data = R"( +let b:B; +-b; +-true; +-false; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, bool>) + | `-(language::name:b:NameProcessor) + +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, bool>) + | `-(language::true_kw:ValueProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, bool>) + `-(language::false_kw:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("N") + { + std::string_view data = R"( +let n:N; +-n; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, unsigned long>) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("Z") + { + std::string_view data = R"( +let i:Z; +-i; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + `-(language::name:i:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R") + { + std::string_view data = R"( +let x:R; +-x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^1") + { + std::string_view data = R"( +let x:R^1; +-x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, TinyVector<1ul, double>, TinyVector<1ul, double> >) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^2") + { + std::string_view data = R"( +let x:R^2; +-x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, TinyVector<2ul, double>, TinyVector<2ul, double> >) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("R^3") + { + std::string_view data = R"( +let x:R^3; +-x; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, TinyVector<3ul, double>, TinyVector<3ul, double> >) + `-(language::name:x:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("not") + { + SECTION("B") + { + std::string_view data = R"( +let b:B; +not b; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::unary_not:UnaryExpressionProcessor<language::unary_not, bool, bool>) + `-(language::name:b:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Errors") + { + SECTION("Invalid unary operator") + { + auto ast = std::make_unique<ASTNode>(); + + REQUIRE_THROWS_WITH(ASTNodeUnaryOperatorExpressionBuilder{*ast}, "unexpected error: undefined unary operator"); + } + + SECTION("Invalid unary operator") + { + auto ast = std::make_unique<ASTNode>(); + + REQUIRE_THROWS_WITH(ASTNodeUnaryOperatorExpressionBuilder{*ast}, "unexpected error: undefined unary operator"); + } + + SECTION("Invalid value type for unary minus") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::unary_minus>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + + REQUIRE_THROWS_WITH(ASTNodeUnaryOperatorExpressionBuilder{*ast}, "undefined value type for unary operator"); + } + + SECTION("errors") + { + CHECK_AST_THROWS_WITH(R"(let n:N; not n;)", "invalid implicit conversion: N -> B"); + CHECK_AST_THROWS_WITH(R"(not 2;)", "invalid implicit conversion: Z -> B"); + CHECK_AST_THROWS_WITH(R"(not -2.3;)", "invalid implicit conversion: R -> B"); + CHECK_AST_THROWS_WITH(R"(not "foo";)", "invalid implicit conversion: string -> B"); + } + + SECTION("Invalid value type for unary not") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::unary_not>(); + ast->children.emplace_back(std::make_unique<ASTNode>()); + + REQUIRE_THROWS_WITH(ASTNodeUnaryOperatorExpressionBuilder{*ast}, "undefined value type for unary operator"); + } + + SECTION("Invalid data type for unary operator") + { + auto ast = std::make_unique<ASTNode>(); + ast->set_type<language::unary_minus>(); + ast->m_data_type = ASTNodeDataType::int_t; + ast->children.emplace_back(std::make_unique<ASTNode>()); + + REQUIRE_THROWS_WITH(ASTNodeUnaryOperatorExpressionBuilder{*ast}, + "unexpected error: invalid operand type for unary operator"); + } + } +} diff --git a/tests/test_ASTPrinter.cpp b/tests/test_ASTPrinter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e08706698313539e133f8cacd3b64145db84866 --- /dev/null +++ b/tests/test_ASTPrinter.cpp @@ -0,0 +1,85 @@ +// -*- coding: utf-8 -*- +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_OUTPUT(data, expected_output, format) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, format}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTPrinter", "[language]") +{ + rang::setControlMode(rang::control::Off); + + SECTION("raw output") + { + std::string_view data = R"( +let n:N, n = 2 + 3; +)"; + + std::string_view result = R"( +(root:undefined) + `-(language::var_declaration:undefined) + +-(language::name:n:undefined) + +-(language::N_set:undefined) + +-(language::name:n:undefined) + `-(language::plus_op:undefined) + +-(language::integer:2:undefined) + `-(language::integer:3:undefined) +)"; + CHECK_OUTPUT(data, result, ASTPrinter::Format::raw); + } + + SECTION("pretty output") + { + std::string_view data = R"( +let n:N, n = 2 + 3; +)"; + + std::string_view result = R"( +(root:undefined) + └──(language::var_declaration:undefined) + ├──(language::name:n:undefined) + ├──(language::N_set:undefined) + ├──(language::name:n:undefined) + └──(language::plus_op:undefined) + ├──(language::integer:2:undefined) + └──(language::integer:3:undefined) +)"; + CHECK_OUTPUT(data, result, ASTPrinter::Format::pretty); + } + + SECTION("escaped sequences") + { + std::string_view data = R"( +let s:string, s = "a string"; +)"; + + std::string_view result = R"( +(root:undefined) + `-(language::var_declaration:undefined) + +-(language::name:s:undefined) + +-(language::string_type:undefined) + +-(language::name:s:undefined) + `-(language::literal:"a string":undefined) +)"; + CHECK_OUTPUT(data, result, ASTPrinter::Format::raw); + } +} diff --git a/tests/test_ASTSymbolInitializationChecker.cpp b/tests/test_ASTSymbolInitializationChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe59815acf5c65c642a81155fa30abf422a5b471 --- /dev/null +++ b/tests/test_ASTSymbolInitializationChecker.cpp @@ -0,0 +1,305 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTSymbolInitializationChecker.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTSymbolInitializationChecker", "[language]") +{ + SECTION("Declarative initialization") + { + std::string_view data = R"( +let m:N, m = 2; +let n:N, n = m ; +let p:N; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_m, found_m] = ast->m_symbol_table->find("m", position); + REQUIRE(found_m); + REQUIRE(symbol_m->attributes().isInitialized()); + + auto [symbol_n, found_n] = ast->m_symbol_table->find("n", position); + REQUIRE(found_n); + REQUIRE(symbol_n->attributes().isInitialized()); + + auto [symbol_p, found_p] = ast->m_symbol_table->find("p", position); + REQUIRE(found_p); + REQUIRE(not symbol_p->attributes().isInitialized()); + } + + SECTION("Array subscript initialization") + { + std::string_view data = R"( +let x:R^3; +x[0] = 1; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_m, found_m] = ast->m_symbol_table->find("x", position); + REQUIRE(found_m); + REQUIRE(symbol_m->attributes().isInitialized()); + } + + SECTION("Declaration plus affectation") + { + std::string_view data = R"( +let z:Z; +let m:N; +let n:N; +n = 2; +m = n; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_m, found_m] = ast->m_symbol_table->find("m", position); + REQUIRE(found_m); + REQUIRE(symbol_m->attributes().isInitialized()); + + auto [symbol_n, found_n] = ast->m_symbol_table->find("n", position); + REQUIRE(found_n); + REQUIRE(symbol_n->attributes().isInitialized()); + + auto [symbol_z, found_z] = ast->m_symbol_table->find("z", position); + REQUIRE(found_z); + REQUIRE(not symbol_z->attributes().isInitialized()); + } + + SECTION("Declarative function initialization") + { + std::string_view data = R"( +let f: R->R, x->x+1; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_m, found_m] = ast->m_symbol_table->find("f", position); + REQUIRE(found_m); + REQUIRE(symbol_m->attributes().isInitialized()); + } + + SECTION("Lists") + { + SECTION("Declarative initialization") + { + std::string_view data = R"( +let (x,y):R*R, (x,y) = (2.3, 4.1); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); + REQUIRE(found_x); + REQUIRE(symbol_x->attributes().isInitialized()); + + auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); + REQUIRE(found_y); + REQUIRE(symbol_y->attributes().isInitialized()); + } + + SECTION("Declarative initialization") + { + std::string_view data = R"( +let x:R^2, x = (2.3, 4.1); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); + REQUIRE(found_x); + REQUIRE(symbol_x->attributes().isInitialized()); + } + + SECTION("Not initialized") + { + std::string_view data = R"( +let(x,y):R*R; +y = 3; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); + REQUIRE(found_x); + REQUIRE(not symbol_x->attributes().isInitialized()); + + auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); + REQUIRE(found_y); + REQUIRE(symbol_y->attributes().isInitialized()); + } + + SECTION("Affectation") + { + std::string_view data = R"( +let (x,y):R*R; +(x,y) = (2.3, 4.1); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); + REQUIRE(found_x); + REQUIRE(symbol_x->attributes().isInitialized()); + + auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); + REQUIRE(found_y); + REQUIRE(symbol_y->attributes().isInitialized()); + } + + SECTION("Affectation") + { + std::string_view data = R"( +let (x,y):R^3*R; +(x,y) = ((2.3, 2, 5), 4.1); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); + REQUIRE(found_x); + REQUIRE(symbol_x->attributes().isInitialized()); + + auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); + REQUIRE(found_y); + REQUIRE(symbol_y->attributes().isInitialized()); + } + } + + SECTION("Affectation") + { + std::string_view data = R"( +let x:R^3; +(x[2], x[1], x[0]) = (1, 2, 3); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTSymbolInitializationChecker{*ast}; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); + REQUIRE(found_x); + REQUIRE(symbol_x->attributes().isInitialized()); + } + + SECTION("errors") + { + SECTION("used uninitialized") + { + std::string_view data = R"( +let n:N; +let m:N, m = n; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"uninitialized symbol 'n'"}); + } + + SECTION("used uninitialized in list affectation") + { + std::string_view data = R"( +let k:N; +let (l, x) : N*R; + +(k, x) = (l, 3.2); +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"uninitialized symbol 'l'"}); + } + + SECTION("used uninitialized in function") + { + std::string_view data = R"( +let y:R; +let f : R->R, x->x+y; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"uninitialized symbol 'y'"}); + } + } +} diff --git a/tests/test_ASTSymbolTableBuilder.cpp b/tests/test_ASTSymbolTableBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0398914c084e4c264bcae9f28f8356ed5885d3dc --- /dev/null +++ b/tests/test_ASTSymbolTableBuilder.cpp @@ -0,0 +1,118 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTSymbolTableBuilder", "[language]") +{ + SECTION("Build symbols") + { + std::string_view data = R"( +let n:N, n = 2; +{ + let m:N, m = n; + let n:R, n = m/3.; +} +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + } + + SECTION("Populate symbol table") + { + std::string_view data = R"( +let b:B; +let n:N; +let z:Z; +let x:R; +let (c0,c1,c2,c3):R*Z*N*B; +let f: R*Z*B->R, (x,n,z) -> x+n; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + + auto root_st = ast->m_symbol_table; + + std::stringstream st_output; + st_output << '\n' << *root_st; + + std::stringstream expected_output; + expected_output << '\n' + << "-- Symbol table state -- parent : " << static_cast<SymbolTable*>(nullptr) << '\n' + << " b: undefined:--\n" + << " n: undefined:--\n" + << " z: undefined:--\n" + << " x: undefined:--\n" + << " c0: undefined:--\n" + << " c1: undefined:--\n" + << " c2: undefined:--\n" + << " c3: undefined:--\n" + << " f: undefined:0\n" + << "------------------------\n"; + + REQUIRE(st_output.str() == expected_output.str()); + } + + SECTION("errors") + { + SECTION("Undeclared symbol") + { + std::string_view data = R"( +let n:N, n = a; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error); + } + + SECTION("Re-declared symbol") + { + std::string_view data = R"( +let n:N, n = 0; +let n:N, n = 1; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error); + } + + SECTION("Re-declared symbol (function)") + { + std::string_view data = R"( +let f:N; +let f : R -> R, x -> 1; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error); + } + + SECTION("Re-declared parameter (function)") + { + std::string_view data = R"( +let f : R*R*N -> R, (x,y,x) -> 1; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error); + } + } +} diff --git a/tests/test_AffectationProcessor.cpp b/tests/test_AffectationProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c94ecdb7d9a1d320dce9f00a7bd70755fd425749 --- /dev/null +++ b/tests/test_AffectationProcessor.cpp @@ -0,0 +1,414 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_AFFECTATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_AFFECTATION_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("AffectationProcessor", "[language]") +{ + SECTION("Affectations") + { + SECTION("B") + { + CHECK_AFFECTATION_RESULT("let b : B; b = true;", "b", true); + } + + SECTION("N") + { + CHECK_AFFECTATION_RESULT("let n : N, n = 1;", "n", 1ul); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let n : N, n = m;", "n", 2ul); + CHECK_AFFECTATION_RESULT("let n : N, n = true;", "n", 1ul); + CHECK_AFFECTATION_RESULT("let n : N, n = false;", "n", 0ul); + } + + SECTION("Z") + { + CHECK_AFFECTATION_RESULT("let z : Z, z = -1;", "z", -1l); + CHECK_AFFECTATION_RESULT("let z : Z, z = true;", "z", 1l); + CHECK_AFFECTATION_RESULT("let z : Z, z = false;", "z", 0l); + } + + SECTION("R") + { + CHECK_AFFECTATION_RESULT("let r : R, r = -1;", "r", double{-1}); + CHECK_AFFECTATION_RESULT("let r : R, r = true;", "r", double{1}); + CHECK_AFFECTATION_RESULT("let r : R, r = false;", "r", double{0}); + CHECK_AFFECTATION_RESULT("let r : R, r = -2.3;", "r", double{-2.3}); + } + + SECTION("R^1") + { + CHECK_AFFECTATION_RESULT("let x : R^1, x = -1;", "x", (TinyVector<1>{-1})); + CHECK_AFFECTATION_RESULT("let x : R^1, x = true;", "x", (TinyVector<1>{true})); + CHECK_AFFECTATION_RESULT("let x : R^1, x = false;", "x", (TinyVector<1>{false})); + CHECK_AFFECTATION_RESULT("let x : R^1, x = -2.3;", "x", (TinyVector<1>{-2.3})); + CHECK_AFFECTATION_RESULT("let x : R^1; x[0] = -1;", "x", (TinyVector<1>{-1})); + CHECK_AFFECTATION_RESULT("let x : R^1; x[0] = true;", "x", (TinyVector<1>{true})); + CHECK_AFFECTATION_RESULT("let x : R^1; x[0] = false;", "x", (TinyVector<1>{false})); + CHECK_AFFECTATION_RESULT("let x : R^1; x[0] = -2.3;", "x", (TinyVector<1>{-2.3})); + + CHECK_AFFECTATION_RESULT("let x : R^1, x = 0;", "x", (TinyVector<1>{zero})); + CHECK_AFFECTATION_RESULT("let x : R^1; x = 0;", "x", (TinyVector<1>{zero})); + } + + SECTION("R^2") + { + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true);", "x", (TinyVector<2>{-1, true})); + CHECK_AFFECTATION_RESULT("let x : R^2, x = (true, false);", "x", (TinyVector<2>{true, false})); + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-0.3, 12);", "x", (TinyVector<2>{-0.3, 12})); + CHECK_AFFECTATION_RESULT("let x : R^2; x[0] = -1; x[1] = true;", "x", (TinyVector<2>{-1, true})); + CHECK_AFFECTATION_RESULT("let x : R^2; x[0] = true; x[1] = false;", "x", (TinyVector<2>{true, false})); + CHECK_AFFECTATION_RESULT("let x : R^2; x[0] = -0.3; x[1] = 12;", "x", (TinyVector<2>{-0.3, 12})); + + CHECK_AFFECTATION_RESULT("let x : R^2, x = 0;", "x", (TinyVector<2>{zero})); + CHECK_AFFECTATION_RESULT("let x : R^2; x = 0;", "x", (TinyVector<2>{zero})); + } + + SECTION("R^3") + { + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-1, true, false);", "x", (TinyVector<3>{-1, true, false})); + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-0.3, 12, 6.2);", "x", (TinyVector<3>{-0.3, 12, 6.2})); + CHECK_AFFECTATION_RESULT("let x : R^3; x[0] = -1; x[1] = true; x[2] = false;", "x", + (TinyVector<3>{-1, true, false})); + CHECK_AFFECTATION_RESULT("let x : R^3; x[0] = -0.3; x[1] = 12; x[2] = 6.2;", "x", (TinyVector<3>{-0.3, 12, 6.2})); + + CHECK_AFFECTATION_RESULT("let x : R^3, x = 0;", "x", (TinyVector<3>{zero})); + CHECK_AFFECTATION_RESULT("let x : R^3; x = 0;", "x", (TinyVector<3>{zero})); + } + } + + SECTION("+=") + { + SECTION("N") + { + CHECK_AFFECTATION_RESULT("let n : N, n = 1; n += 3;", "n", 4ul); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let n : N, n = 1; n += m;", "n", 3ul); + CHECK_AFFECTATION_RESULT("let n : N, n = 1; n += true;", "n", 2ul); + CHECK_AFFECTATION_RESULT("let n : N, n = 3; n += false;", "n", 3ul); + } + + SECTION("Z") + { + CHECK_AFFECTATION_RESULT("let z : Z, z = 1; z += 3;", "z", 4l); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let z : Z, z = 1; z += m;", "z", 3l); + CHECK_AFFECTATION_RESULT("let z : Z, z = 1; z += true;", "z", 2l); + CHECK_AFFECTATION_RESULT("let z : Z, z = 3; z += false;", "z", 3l); + } + + SECTION("R") + { + CHECK_AFFECTATION_RESULT("let r : R, r = 1.2; r += 2.3;", "r", 3.5); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let r : R, r = 1.3; r += m;", "r", 3.3); + CHECK_AFFECTATION_RESULT("let r : R, r = 1.1; r += true;", "r", 2.1); + CHECK_AFFECTATION_RESULT("let r : R, r = 3.3; r += false;", "r", 3.3); + CHECK_AFFECTATION_RESULT("let r : R, r = 2; r += 1.1;", "r", 3.1); + } + + SECTION("R^1") + { + CHECK_AFFECTATION_RESULT("let x : R^1, x = -1; let y : R^1, y = 1; x += y;", "x", + (TinyVector<1>{-1} + TinyVector<1>{1})); + CHECK_AFFECTATION_RESULT("let x : R^1, x = 2; x[0] += 1;", "x", (TinyVector<1>{2} + TinyVector<1>{1})); + } + + SECTION("R^2") + { + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true); let y : R^2, y = (1,3); x += y;", "x", + (TinyVector<2>{-1, true} + TinyVector<2>{1, 3})); + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true); x[0] += 2; x[1] += 1;", "x", + (TinyVector<2>{-1, true} + TinyVector<2>{2, 1})); + } + + SECTION("R^3") + { + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-1, true, false); let y : R^3, y = (1,2,3); x += y;", "x", + (TinyVector<3>{-1, true, false} + TinyVector<3>{1, 2, 3})); + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-0.3, 12, 6.2); x[0] += 1; x[1] += -3; x[2] += 1;", "x", + (TinyVector<3>{-0.3, 12, 6.2} + TinyVector<3>{1, -3, 1})); + } + } + + SECTION("-=") + { + SECTION("N") + { + CHECK_AFFECTATION_RESULT("let n : N, n = 3; n -= 2;", "n", 1ul); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let n : N, n = 4; n -= m;", "n", 2ul); + CHECK_AFFECTATION_RESULT("let n : N, n = 1; n -= true;", "n", 0ul); + CHECK_AFFECTATION_RESULT("let n : N, n = 3; n -= false;", "n", 3ul); + } + + SECTION("Z") + { + CHECK_AFFECTATION_RESULT("let z : Z, z = 1; z -= 3;", "z", -2l); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let z : Z, z = 1; z -= m;", "z", -1l); + CHECK_AFFECTATION_RESULT("let z : Z, z = 1; z -= true;", "z", 0l); + CHECK_AFFECTATION_RESULT("let z : Z, z = 3; z -= false;", "z", 3l); + } + + SECTION("R") + { + CHECK_AFFECTATION_RESULT("let r : R, r = 1.1; r -= 2;", "r", (1.1 - 2l)); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let r : R, r = 1.3; r -= m;", "r", (1.3 - 2ul)); + CHECK_AFFECTATION_RESULT("let r : R, r = 1.1; r -= true;", "r", (1.1 - true)); + CHECK_AFFECTATION_RESULT("let r : R, r = 3.3; r -= false;", "r", 3.3); + CHECK_AFFECTATION_RESULT("let r : R, r = 2; r -= 1.1;", "r", (2. - 1.1)); + } + + SECTION("R^1") + { + CHECK_AFFECTATION_RESULT("let x : R^1, x = -1; let y : R^1, y = 1; x -= y;", "x", + (TinyVector<1>{-1} - TinyVector<1>{1})); + CHECK_AFFECTATION_RESULT("let x : R^1, x = 2; x[0] -= 1;", "x", (TinyVector<1>{2} - TinyVector<1>{1})); + } + + SECTION("R^2") + { + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true); let y : R^2, y = (1,3); x -= y;", "x", + (TinyVector<2>{-1, true} - TinyVector<2>{1, 3})); + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true); x[0] -= 2; x[1] -= 1;", "x", + (TinyVector<2>{-1, true} - TinyVector<2>{2, 1})); + } + + SECTION("R^3") + { + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-1, true, false); let y : R^3, y = (1,2,3); x-=y;", "x", + (TinyVector<3>{-1, true, false} - TinyVector<3>{1, 2, 3})); + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-0.3, 12, 6.2); x[0] -= 1; x[1] -= -3; x[2] -= 1;", "x", + (TinyVector<3>{-0.3, 12, 6.2} - TinyVector<3>{1, -3, 1})); + } + } + + SECTION("*=") + { + SECTION("N") + { + CHECK_AFFECTATION_RESULT("let n : N, n = 3; n *= 2;", "n", 6ul); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let n : N, n = 4; n *= m;", "n", 8ul); + CHECK_AFFECTATION_RESULT("let n : N, n = 1; n *= true;", "n", 1ul); + CHECK_AFFECTATION_RESULT("let n : N, n = 3; n *= false;", "n", 0ul); + } + + SECTION("Z") + { + CHECK_AFFECTATION_RESULT("let z : Z, z = 1; z *= 3;", "z", 3l); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let z : Z, z = -2; z *= m;", "z", -4l); + CHECK_AFFECTATION_RESULT("let z : Z, z = 1; z *= true;", "z", 1l); + CHECK_AFFECTATION_RESULT("let z : Z, z = 3; z *= false;", "z", 0l); + } + + SECTION("R") + { + CHECK_AFFECTATION_RESULT("let r : R, r = 1.1; r *= 2;", "r", (1.1 * 2l)); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let r : R, r = 1.3; r *= m;", "r", (1.3 * 2ul)); + CHECK_AFFECTATION_RESULT("let r : R, r = 1.1; r *= true;", "r", (1.1 * true)); + CHECK_AFFECTATION_RESULT("let r : R, r = 3.3; r *= false;", "r", (3.3 * false)); + CHECK_AFFECTATION_RESULT("let r : R, r = 2; r *= 1.1;", "r", (2. * 1.1)); + } + + SECTION("R^1") + { + CHECK_AFFECTATION_RESULT("let x : R^1, x = 2; x *= 2;", "x", (TinyVector<1>{TinyVector<1>{2} *= 2})); + CHECK_AFFECTATION_RESULT("let x : R^1, x = 2; x[0] *= 1.3;", "x", (TinyVector<1>{2 * 1.3})); + } + + SECTION("R^2") + { + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true); x *= 3;", "x", + (TinyVector<2>{TinyVector<2>{-1, true} *= 3})); + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true); x[0] *= 2; x[1] *= 3;", "x", + (TinyVector<2>{-1 * 2, true * 3})); + } + + SECTION("R^3") + { + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-1, true, false); x*=5.2;", "x", + (TinyVector<3>{TinyVector<3>{-1, true, false} *= 5.2})); + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-0.3, 12, 6.2); x[0] *= -1; x[1] *= -3; x[2] *= 2;", "x", + (TinyVector<3>{-0.3 * -1, 12 * -3, 6.2 * 2})); + } + } + + SECTION("/=") + { + SECTION("N") + { + CHECK_AFFECTATION_RESULT("let n : N, n = 4; n /= 2;", "n", 2ul); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let n : N, n = 6; n /= m;", "n", 3ul); + CHECK_AFFECTATION_RESULT("let n : N, n = 1; n /= true;", "n", 1ul); + } + + SECTION("Z") + { + CHECK_AFFECTATION_RESULT("let z : Z, z = 7; z /= -3;", "z", -2l); + CHECK_AFFECTATION_RESULT("let m : N, m = 3; let z : Z, z = 6; z /= m;", "z", 2l); + CHECK_AFFECTATION_RESULT("let z : Z, z = 6; z /= true;", "z", 6l); + } + + SECTION("R") + { + CHECK_AFFECTATION_RESULT("let r : R, r = 1.1; r /= 2;", "r", (1.1 / 2l)); + CHECK_AFFECTATION_RESULT("let m : N, m = 2; let r : R, r = 1.3; r /= m;", "r", (1.3 / 2ul)); + CHECK_AFFECTATION_RESULT("let r : R, r = 1.1; r /= true;", "r", (1.1 / true)); + CHECK_AFFECTATION_RESULT("let r : R, r = 2; r /= 1.1;", "r", (2. / 1.1)); + } + + SECTION("R^1") + { + CHECK_AFFECTATION_RESULT("let x : R^1, x = 2; x[0] /= 1.3;", "x", (TinyVector<1>{2 / 1.3})); + } + + SECTION("R^2") + { + CHECK_AFFECTATION_RESULT("let x : R^2, x = (-1, true); x[0] /= 2; x[1] /= 3;", "x", + (TinyVector<2>{-1. / 2., true / 3.})); + } + + SECTION("R^3") + { + CHECK_AFFECTATION_RESULT("let x : R^3, x = (-0.3, 12, 6.2); x[0] /= -1.2; x[1] /= -3.1; x[2] /= 2.4;", "x", + (TinyVector<3>{-0.3 / -1.2, 12 / -3.1, 6.2 / 2.4})); + } + } + + SECTION("errors") + { + SECTION("invalid implicit conversions") + { + SECTION("-> B") + { + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 1; let b : B; b = n;", "invalid implicit conversion: N -> B"); + CHECK_AFFECTATION_THROWS_WITH("let b : B; b = 1;", "invalid implicit conversion: Z -> B"); + CHECK_AFFECTATION_THROWS_WITH("let b : B; b = 2.3;", "invalid implicit conversion: R -> B"); + CHECK_AFFECTATION_THROWS_WITH("let b : B; b = \"foo\";", "invalid implicit conversion: string -> B"); + } + + SECTION("-> N") + { + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2.3;", "invalid implicit conversion: R -> N"); + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = \"bar\";", "invalid implicit conversion: string -> N"); + + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n += 1.1;", "invalid implicit conversion: R -> N"); + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n += \"foo\";", "invalid implicit conversion: string -> N"); + + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n -= 1.1;", "invalid implicit conversion: R -> N"); + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n -= \"bar\";", "invalid implicit conversion: string -> N"); + + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n *= 2.51;", "invalid implicit conversion: R -> N"); + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n *= \"foobar\";", "invalid implicit conversion: string -> N"); + + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n /= 2.51;", "invalid implicit conversion: R -> N"); + CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n /= \"foo\";", "invalid implicit conversion: string -> N"); + } + + SECTION("-> Z") + { + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = -2.3;", "invalid implicit conversion: R -> Z"); + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = \"foobar\";", "invalid implicit conversion: string -> Z"); + + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 2; z += 1.1;", "invalid implicit conversion: R -> Z"); + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 2; z += \"foo\";", "invalid implicit conversion: string -> Z"); + + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 2; z -= 2.1;", "invalid implicit conversion: R -> Z"); + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 2; z -= \"bar\";", "invalid implicit conversion: string -> Z"); + + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 2; z *= -2.51;", "invalid implicit conversion: R -> Z"); + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 2; z *= \"foobar\";", "invalid implicit conversion: string -> Z"); + + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 4; z /= -2.;", "invalid implicit conversion: R -> Z"); + CHECK_AFFECTATION_THROWS_WITH("let z : Z, z = 2; z /= \"foo\";", "invalid implicit conversion: string -> Z"); + } + + SECTION("-> R") + { + CHECK_AFFECTATION_THROWS_WITH("let x : R, x = \"foobar\";", "invalid implicit conversion: string -> R"); + CHECK_AFFECTATION_THROWS_WITH("let x : R, x = 2.3; x += \"foo\";", "invalid implicit conversion: string -> R"); + CHECK_AFFECTATION_THROWS_WITH("let x : R, x = 2.1; x -= \"bar\";", "invalid implicit conversion: string -> R"); + CHECK_AFFECTATION_THROWS_WITH("let x : R, x = 1.2; x *= \"foobar\";", + "invalid implicit conversion: string -> R"); + CHECK_AFFECTATION_THROWS_WITH("let x : R, x =-2.3; x /= \"foo\";", "invalid implicit conversion: string -> R"); + } + + SECTION("-> R^n") + { + CHECK_AFFECTATION_THROWS_WITH("let x : R^2, x = \"foobar\";", "invalid implicit conversion: string -> R^2"); + CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = \"foobar\";", "invalid implicit conversion: string -> R^3"); + + CHECK_AFFECTATION_THROWS_WITH("let x : R^2, x = 3.2;", "invalid implicit conversion: R -> R^2"); + CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = 2.3;", "invalid implicit conversion: R -> R^3"); + + CHECK_AFFECTATION_THROWS_WITH("let x : R^2, x = 4;", "invalid implicit conversion: Z -> R^2"); + CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = 3;", "invalid implicit conversion: Z -> R^3"); + + CHECK_AFFECTATION_THROWS_WITH("let x : R^1, x = 0; let y : R^2, y = x;", + "incompatible dimensions in affectation"); + CHECK_AFFECTATION_THROWS_WITH("let x : R^1, x = 0; let y : R^3, y = x;", + "incompatible dimensions in affectation"); + + CHECK_AFFECTATION_THROWS_WITH("let x : R^2, x = 0; let y : R^1, y = x;", + "incompatible dimensions in affectation"); + CHECK_AFFECTATION_THROWS_WITH("let x : R^2, x = 0; let y : R^3, y = x;", + "incompatible dimensions in affectation"); + + CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = 0; let y : R^1, y = x;", + "incompatible dimensions in affectation"); + CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = 0; let y : R^2, y = x;", + "incompatible dimensions in affectation"); + } + } + } +} diff --git a/tests/test_AffectationToStringProcessor.cpp b/tests/test_AffectationToStringProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4053e023187944c87333f0dd605404104d039aa2 --- /dev/null +++ b/tests/test_AffectationToStringProcessor.cpp @@ -0,0 +1,99 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_AFFECTATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTAffectationToStringProcessor", "[language]") +{ + SECTION("Affectations") + { + CHECK_AFFECTATION_RESULT(R"(let s : string; s = "foo";)", "s", std::string("foo")); + CHECK_AFFECTATION_RESULT(R"(let n : N, n = 2; let s : string; s = n;)", "s", std::to_string(2ul)); + CHECK_AFFECTATION_RESULT(R"(let s : string; s = -1;)", "s", std::to_string(-1l)); + CHECK_AFFECTATION_RESULT(R"(let s : string; s = true;)", "s", std::to_string(true)); + CHECK_AFFECTATION_RESULT(R"(let s : string; s = 2.3;)", "s", std::to_string(2.3)); + { + std::ostringstream os; + os << TinyVector<1>{13} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let x : R^1, x = 13; let s : string; s = x;)", "s", os.str()); + } + { + std::ostringstream os; + os << TinyVector<2>{2, 3} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let x : R^2, x = (2,3); let s : string; s = x;)", "s", os.str()); + } + { + std::ostringstream os; + os << TinyVector<3>{1, 2, 3} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let x : R^3, x = (1,2,3); let s : string; s = x;)", "s", os.str()); + } + } + + SECTION("+=") + { + CHECK_AFFECTATION_RESULT(R"(let s : string, s = "foo"; s += "bar";)", "s", std::string("foobar")); + CHECK_AFFECTATION_RESULT(R"(let n : N, n = 2; let s : string, s = "foo"; s += n;)", "s", + (std::string("foo") + std::to_string(2ul))); + CHECK_AFFECTATION_RESULT(R"(let s : string, s = "foo"; s += -1;)", "s", (std::string("foo") + std::to_string(-1l))); + CHECK_AFFECTATION_RESULT(R"(let s : string, s = "foo"; s += true;)", "s", + (std::string("foo") + std::to_string(true))); + CHECK_AFFECTATION_RESULT(R"(let s : string, s = "foo"; s += 2.3;)", "s", + (std::string("foo") + std::to_string(2.3))); + { + std::ostringstream os; + os << "foo" << TinyVector<1>{13} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let x : R^1, x = 13; let s : string, s="foo"; s += x;)", "s", os.str()); + } + { + std::ostringstream os; + os << "foo" << TinyVector<2>{2, 3} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let x : R^2, x = (2,3); let s : string, s="foo"; s += x;)", "s", os.str()); + } + { + std::ostringstream os; + os << "foo" << TinyVector<3>{1, 2, 3} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let x : R^3, x = (1,2,3); let s : string, s="foo"; s += x;)", "s", os.str()); + } + } +} diff --git a/tests/test_ArraySubscriptProcessor.cpp b/tests/test_ArraySubscriptProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a48390214ac9cfd38bfa063613c0dc2880fe1f6a --- /dev/null +++ b/tests/test_ArraySubscriptProcessor.cpp @@ -0,0 +1,160 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_EVALUATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_EVALUATION_THROWS_WITH(data, error_message) \ + { \ + auto eval = [&] { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + }; \ + \ + REQUIRE_THROWS_WITH(eval(), error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ArraySubscriptProcessor", "[language]") +{ + SECTION("R^1 component access") + { + std::string_view data = R"( +let x : R^1, x = 1; +let x0: R, x0 = x[0]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + } + + SECTION("R^2 component access") + { + std::string_view data = R"( +let x : R^2, x = (1,2); +let x0: R, x0 = x[0]; +let x1: R, x1 = x[1]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + CHECK_EVALUATION_RESULT(data, "x1", double{2}); + } + + SECTION("R^3 component access") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let x0 : R, x0 = x[0]; +let x1 : R, x1 = x[1]; +let x2 : R, x2 = x[2]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + CHECK_EVALUATION_RESULT(data, "x1", double{2}); + CHECK_EVALUATION_RESULT(data, "x2", double{3}); + } + + SECTION("R^d component access from integer expression") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let x0: R, x0 = x[3-2-1]; + +let y : R^2, y = (2,7); +let y1: R, y1 = y[2/2]; + +let z : R^1, z = 8; +let z0: R, z0 = z[(2-2)*1]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + CHECK_EVALUATION_RESULT(data, "y1", double{7}); + CHECK_EVALUATION_RESULT(data, "z0", double{8}); + } + + SECTION("error invalid index type") + { + SECTION("R index type") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let x0: R, x0 = x[2.3]; +)"; + + CHECK_EVALUATION_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); + } + + SECTION("string index type") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let x0: R, x0 = x["foo"]; +)"; + + CHECK_EVALUATION_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> Z"}); + } + + SECTION("R^d index type") + { + std::string_view data = R"( +let x : R^3, x = (1,2,3); +let x0: R, x0 = x[x]; +)"; + + CHECK_EVALUATION_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> Z"}); + } + } +} diff --git a/tests/test_BinaryExpressionProcessor_arithmetic.cpp b/tests/test_BinaryExpressionProcessor_arithmetic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b3f3bb07597b9d2f6704c117cc02ff6d02743a6 --- /dev/null +++ b/tests/test_BinaryExpressionProcessor_arithmetic.cpp @@ -0,0 +1,153 @@ +#include <catch2/catch.hpp> + +#include <test_BinaryExpressionProcessor_utils.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("BinaryExpressionProcessor arithmetic", "[language]") +{ + SECTION("+") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = true + true;)", "z", 2l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; n = true + 1;)", "n", 2ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; n = true + 1;)", "n", 2ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; n = false + 1;)", "n", 1ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = true + 3;)", "z", 4l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = false + 3;)", "z", 3l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = false + 3.6;)", "r", 3.6); + CHECK_BINARY_EXPRESSION_RESULT(R"(let s:R, s = -3.3; let r:R, r = true + s;)", "r", -2.3); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; n = n + true;)", "n", 2ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; n = n + m;)", "n", 6ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let z:Z, z = -1; n = n + z;)", "n", 3ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let x:R, x = n + 2.3;)", "x", 3.3); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = -1 + true;)", "z", 0l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let z:Z, z = -3 + n;)", "z", 1l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let z:Z, z = -3 + n;)", "z", -1l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = 1 + 2;)", "z", 3l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let x:R, x = 3 + 2.5;)", "x", 5.5); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 + true;)", "r", (-1.2 + true)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let r:R, r = -1.2 + n;)", "r", (-1.2 + uint64_t{2})); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 + 1;)", "r", (-1.2 + 1)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 + 2.3;)", "r", (-1.2 + 2.3)); + } + } + + SECTION("-") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = true - false;)", "n", 1ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; n = true - n;)", "n", 0ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = false - 1;)", "z", -1l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = true - 1.2;)", "r", (true - 1.2)); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; n = n - true;)", "n", 2ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; n = n - m;)", "n", 2ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 5; n = n - 4;)", "n", 1ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; let x:R, x = n - 2.3;)", "x", double{3ul - 2.3}); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = -1 - true;)", "z", -2l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let z:Z, z = 3 - n;)", "z", -1l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = 7 - 2;)", "z", 5l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let x:R, x = 4 - 2.5;)", "x", 1.5); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 - true;)", "r", (-1.2 - true)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let r:R, r = -1.2 - n;)", "r", (-1.2 - uint64_t{2})); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 - 1;)", "r", (-1.2 - 1)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 - 2.3;)", "r", (-1.2 - 2.3)); + } + } + + SECTION("*") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = true * false;)", "n", 0ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; n = true * n;)", "n", 2ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = false * 1;)", "z", 0l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = true * 1.2;)", "r", (true * 1.2)); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; n = n * true;)", "n", 3ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; n = n * m;)", "n", 8ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 5; n = n * 4;)", "n", 20ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; let x:R, x = n * 2.3;)", "x", double{3ul * 2.3}); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = -1 * true;)", "z", -1l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let z:Z, z = 3 * n;)", "z", 12l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = 7 * 2;)", "z", 14l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let x:R, x = 4 * 2.4;)", "x", double{4l * 2.4}); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 * true;)", "r", (-1.2 * true)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let r:R, r = -1.2 * n;)", "r", (-1.2 * uint64_t{2})); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 * 11;)", "r", (-1.2 * 11)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 * 2.3;)", "r", (-1.2 * 2.3)); + } + } + + SECTION("/") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = false / true;)", "n", 0ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; n = true / n;)", "n", 0ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = false / 1;)", "z", 0l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = true / 1.2;)", "r", (true / 1.2)); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; n = n / true;)", "n", 3ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; n = n / m;)", "n", 2ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 5; n = n / 4;)", "n", 1ul); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; let x:R, x = n / 2.3;)", "x", double{3ul / 2.3}); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = -1 / true;)", "z", -1l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let z:Z, z = 3 / n;)", "z", 0l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let z:Z, z = 7 / 2;)", "z", 3l); + CHECK_BINARY_EXPRESSION_RESULT(R"(let x:R, x = 4 / 2.4;)", "x", double{4l / 2.4}); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 / true;)", "r", (-1.2 / true)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let r:R, r = -1.2 / n;)", "r", (-1.2 / uint64_t{2})); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 / 11;)", "r", (-1.2 / 11)); + CHECK_BINARY_EXPRESSION_RESULT(R"(let r:R, r = -1.2 / 2.3;)", "r", (-1.2 / 2.3)); + } + } +} diff --git a/tests/test_BinaryExpressionProcessor_comparison.cpp b/tests/test_BinaryExpressionProcessor_comparison.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c74d73f919f557fc992812848e9eb7a9afa1fd31 --- /dev/null +++ b/tests/test_BinaryExpressionProcessor_comparison.cpp @@ -0,0 +1,301 @@ +#include <catch2/catch.hpp> + +#include <test_BinaryExpressionProcessor_utils.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("BinaryExpressionProcessor comparison", "[language]") +{ + SECTION("<") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true < true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false < true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true < true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false < false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = true < n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = true < n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = false < n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = false < n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true < 3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true < 0;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false < 0;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false < 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false < 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true < 1.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false < 0.1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true < -1.7;)", "b", false); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n < true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n < true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n < false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n < false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; let b:B, b = n < m;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let m:N, m = 2; let b:B, b = n < m;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let m:N, m = 0; let b:B, b = n < m;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n < 4;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n < 5;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n < 2.3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n < 1.;)", "b", false); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 < true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 < false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1 < false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = -3 < n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = 0 < n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 < 2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 < 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 < 3.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 < 3.1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 < 2.5;)", "b", false); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 < true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 < false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. < true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0. < false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = -1.2 < n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = 0. < n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 < 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. < 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 < -1.1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 < -1.2;)", "b", false); + } + } + + SECTION("<=") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true <= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false <= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false <= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true <= false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = true <= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = true <= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = true <= n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = false <= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = false <= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true <= 3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true <= 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true <= 0;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false <= 0;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false <= 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false <= -1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false <= 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true <= 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false <= 0.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true <= 0.5;)", "b", false); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = n <= true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n <= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n <= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n <= false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n <= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; let b:B, b = n <= m;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let m:N, m = 2; let b:B, b = n <= m;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n <= 5;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n <= 4;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n <= 3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n <= 2.3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n <= 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n <= 0.5;)", "b", false); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 2 <= true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 <= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 <= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 <= false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = 4 <= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = 5 <= n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 2 <= 2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 <= 2;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 <= 3.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 <= 3.1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 <= 2.5;)", "b", false); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 <= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 <= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. <= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1.1 <= true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0. <= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0.1 <= false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = 2. <= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = 2.1 <= n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = 0.7 <= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -2 <= -2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1 <= -2;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 <= -1.1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 <= -1.2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. <= -1.2;)", "b", false); + } + } + + SECTION(">") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true > true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false > true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true > false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false > false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = true > n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = true > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = true > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = false > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = false > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true > 3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true > 0;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false > 0;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false > 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false > 1.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true > 1.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false > 0.1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true > -1.7;)", "b", true); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n > true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = n > true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n > false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n > false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; let b:B, b = n > m;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let m:N, m = 2; let b:B, b = n > m;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let m:N, m = 0; let b:B, b = n > m;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n > 4;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n > 3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n > 2.3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n > 1.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n > 0.3;)", "b", true); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 > true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 > false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 > false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 2 > true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = -3 > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = 0 > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = 1 > n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 > 2;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 > 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 2 > 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 > 3.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 > 3.1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 > 2.5;)", "b", true); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1.2 > true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0.2 > false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. > true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0. > false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = -2.2 > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = 0. > n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1.2 > 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. > 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1. > -1.1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 > -1.1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 > -1.2;)", "b", false); + } + } + + SECTION(">=") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = true >= n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = true >= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = true >= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = false >= n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = false >= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= 3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= 0;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= 0;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= -1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= 1.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= 0.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= 0.5;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false >= 0.1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true >= 1.5;)", "b", false); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = n >= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n >= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n >= true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; let b:B, b = n >= m;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let m:N, m = 2; let b:B, b = n >= m;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n >= 5;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n >= 4;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n >= 3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n >= 2.3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n >= 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n >= 0.5;)", "b", true); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 2 >= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 >= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 >= true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = 4 >= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = 3 >= n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 2 >= 2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 >= 2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 >= 3.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 >= 3.1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 >= 2.5;)", "b", true); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 >= true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 >= false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. >= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1.1 >= true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0. >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0.1 >= false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = 2. >= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = 2.1 >= n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = 0.7 >= n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -2 >= -2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1 >= -2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 >= -1.1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 >= -1.2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. >= -1.2;)", "b", true); + } + } +} diff --git a/tests/test_BinaryExpressionProcessor_equality.cpp b/tests/test_BinaryExpressionProcessor_equality.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7d526b97939bb64998bc6d8b961a2a042999de4 --- /dev/null +++ b/tests/test_BinaryExpressionProcessor_equality.cpp @@ -0,0 +1,140 @@ +#include <catch2/catch.hpp> + +#include <test_BinaryExpressionProcessor_utils.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("BinaryExpressionProcessor equality", "[language]") +{ + SECTION("==") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true == true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false == true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true == false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false == false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = true == n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = true == n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = false == n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = false == n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true == 3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true == 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false == 0;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false == 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false == 1.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true == 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false == 0.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true == -1.7;)", "b", false); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n == true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n == true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n == false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n == false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; let b:B, b = n == m;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let m:N, m = 2; let b:B, b = n == m;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n == 4;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n == 5;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n == 2.3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n == 1.;)", "b", true); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 == true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 == false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 == true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 == false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = -3 == n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; let b:B, b = 3 == n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 == 2;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 11 == 11;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 == 2.5;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 == 3.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 == 3.5;)", "b", false); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 == true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. == true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0.1 == false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0. == false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = -1.2 == n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = 2. == n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 == 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -2. == -2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 == 2.3;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 == -1.2;)", "b", true); + } + } + + SECTION("!=") + { + SECTION("lhs is B") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true != true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false != true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true != false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false != false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = true != n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = true != n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = false != n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = false != n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true != 3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true != 1;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false != 0;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false != 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false != 1.;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true != 1.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false != 0.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true != -1.7;)", "b", true); + } + + SECTION("lhs is N") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n != true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n != true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n != false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 0; let b:B, b = n != false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let m:N, m = 2; let b:B, b = n != m;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let m:N, m = 2; let b:B, b = n != m;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n != 4;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = n != 5;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n != 2.3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 1; let b:B, b = n != 1.;)", "b", false); + } + + SECTION("lhs is Z") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 != true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 != false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 != true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0 != false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 4; let b:B, b = -3 != n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 3; let b:B, b = 3 != n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1 != 2;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 11 != 11;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 != 2.5;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 != 3.;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 3 != 3.5;)", "b", true); + } + + SECTION("lhs is R") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 != true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 1. != true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0.1 != false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = 0. != false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = -1.2 != n;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let b:B, b = 2. != n;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 != 1;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -2. != -2;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 != 2.3;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = -1.2 != -1.2;)", "b", false); + } + } +} diff --git a/tests/test_BinaryExpressionProcessor_logic.cpp b/tests/test_BinaryExpressionProcessor_logic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f53d8557cc48551a9abe630c3bbda43aed9ae366 --- /dev/null +++ b/tests/test_BinaryExpressionProcessor_logic.cpp @@ -0,0 +1,74 @@ +#include <catch2/catch.hpp> + +#include <test_BinaryExpressionProcessor_utils.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("BinaryExpressionProcessor logic", "[language]") +{ + SECTION("and") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true and true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false and true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true and false;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false and false;)", "b", false); + + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = (2<3) and ((3.2-1) != 2);)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = (1>4) and true;)", "b", false); + } + + SECTION("or") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true or true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false or true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true or false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false or false;)", "b", false); + + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = (2<3) and ((3.2-1) != 2);)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = (1>4) or true;)", "b", true); + } + + SECTION("xor") + { + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true xor true;)", "b", false); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false xor true;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = true xor false;)", "b", true); + CHECK_BINARY_EXPRESSION_RESULT(R"(let b:B, b = false xor false;)", "b", false); + } + + SECTION("errors") + { + SECTION("bad implicit conversion") + { + SECTION("and") + { + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(let n:N, n=1; n and true;)", "invalid implicit conversion: N -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(let n:N, n=2; false and n;)", "invalid implicit conversion: N -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(1 and true;)", "invalid implicit conversion: Z -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(false and 2;)", "invalid implicit conversion: Z -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(1.1 and true;)", "invalid implicit conversion: R -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(false and 2e-2;)", "invalid implicit conversion: R -> B"); + } + + SECTION("or") + { + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(let n:N, n=1; n or true;)", "invalid implicit conversion: N -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(let n:N, n=2; false or n;)", "invalid implicit conversion: N -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(1 or true;)", "invalid implicit conversion: Z -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(false or 2;)", "invalid implicit conversion: Z -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(1.1 or true;)", "invalid implicit conversion: R -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(false or 2e-2;)", "invalid implicit conversion: R -> B"); + } + + SECTION("xor") + { + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(let n:N, n=1; n xor true;)", "invalid implicit conversion: N -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(let n:N, n=2; false xor n;)", "invalid implicit conversion: N -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(1 xor true;)", "invalid implicit conversion: Z -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(false xor 2;)", "invalid implicit conversion: Z -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(1.1 xor true;)", "invalid implicit conversion: R -> B"); + CHECK_BINARY_EXPRESSION_THROWS_WITH(R"(false xor 2e-2;)", "invalid implicit conversion: R -> B"); + } + } + } +} diff --git a/tests/test_BinaryExpressionProcessor_utils.hpp b/tests/test_BinaryExpressionProcessor_utils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..176c91344be48d261282171eb460b7c7a358d2dd --- /dev/null +++ b/tests/test_BinaryExpressionProcessor_utils.hpp @@ -0,0 +1,54 @@ +#ifndef TEST_BINARY_EXPRESSION_PROCESSOR_UTILS_HPP +#define TEST_BINARY_EXPRESSION_PROCESSOR_UTILS_HPP + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_BINARY_EXPRESSION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_BINARY_EXPRESSION_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +#endif // TEST_BINARY_EXPRESSION_PROCESSOR_UTILS_HPP diff --git a/tests/test_BreakProcessor.cpp b/tests/test_BreakProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6cefebec47eb216847f1115406a3456d3ea2d421 --- /dev/null +++ b/tests/test_BreakProcessor.cpp @@ -0,0 +1,22 @@ +#include <catch2/catch.hpp> + +#include <language/node_processor/BreakProcessor.hpp> + +#include <rang.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("BreakProcessor", "[language]") +{ + rang::setControlMode(rang::control::Off); + + ExecutionPolicy exec_policy; + + REQUIRE(exec_policy.exec() == true); + + BreakProcessor break_processor; + break_processor.execute(exec_policy); + + REQUIRE(exec_policy.exec() == false); + REQUIRE(exec_policy.jumpType() == ExecutionPolicy::JumpType::break_jump); +} diff --git a/tests/test_BuiltinFunctionEmbedder.cpp b/tests/test_BuiltinFunctionEmbedder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf0445d6aadf5cfdbefed9134dafe0e89dd8d290 --- /dev/null +++ b/tests/test_BuiltinFunctionEmbedder.cpp @@ -0,0 +1,285 @@ +#include <catch2/catch.hpp> + +#include <language/utils/BuiltinFunctionEmbedder.hpp> + +// clazy:excludeall=non-pod-global-static + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t, + "shared_const_double"}; + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<double>> = {ASTNodeDataType::type_id_t, "shared_double"}; + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<uint64_t>> = {ASTNodeDataType::type_id_t, + "shared_uint64_t"}; + +TEST_CASE("BuiltinFunctionEmbedder", "[language]") +{ + rang::setControlMode(rang::control::Off); + + SECTION("math") + { + BuiltinFunctionEmbedder<double(double)> embedded_sin{[](double x) -> double { return std::sin(x); }}; + + double arg = 2; + DataVariant arg_variant = arg; + + DataVariant result = embedded_sin.apply({arg_variant}); + + REQUIRE(std::get<double>(result) == std::sin(arg)); + REQUIRE(embedded_sin.numberOfParameters() == 1); + + REQUIRE(embedded_sin.getReturnDataType() == ASTNodeDataType::double_t); + REQUIRE(embedded_sin.getParameterDataTypes()[0] == ASTNodeDataType::double_t); + } + + SECTION("multiple variant args") + { + std::function c = [](double x, uint64_t i) -> bool { return x > i; }; + + BuiltinFunctionEmbedder<bool(double, uint64_t)> embedded_c{c}; + + double d_arg = 2.3; + uint64_t i_arg = 3; + + std::vector<DataVariant> args; + args.push_back(d_arg); + args.push_back(i_arg); + + DataVariant result = embedded_c.apply(args); + + REQUIRE(std::get<bool>(result) == c(d_arg, i_arg)); + REQUIRE(embedded_c.numberOfParameters() == 2); + + REQUIRE(embedded_c.getReturnDataType() == ASTNodeDataType::bool_t); + REQUIRE(embedded_c.getParameterDataTypes()[0] == ASTNodeDataType::double_t); + REQUIRE(embedded_c.getParameterDataTypes()[1] == ASTNodeDataType::unsigned_int_t); + } + + SECTION("POD BuiltinFunctionEmbedder") + { + std::function c = [](double x, uint64_t i) -> bool { return x > i; }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = + std::make_unique<BuiltinFunctionEmbedder<bool(double, uint64_t)>>(c); + + double d_arg = 2.3; + uint64_t i_arg = 3; + + std::vector<DataVariant> args; + args.push_back(d_arg); + args.push_back(i_arg); + + DataVariant result = i_embedded_c->apply(args); + + REQUIRE(std::get<bool>(result) == c(d_arg, i_arg)); + REQUIRE(i_embedded_c->numberOfParameters() == 2); + + REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::bool_t); + REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::double_t); + REQUIRE(i_embedded_c->getParameterDataTypes()[1] == ASTNodeDataType::unsigned_int_t); + } + + SECTION("void(double) BuiltinFunctionEmbedder") + { + double y = 1; + + std::function add_to_y = [&](double x) -> void { y += x; }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = + std::make_unique<BuiltinFunctionEmbedder<void(double)>>(add_to_y); + + double x = 0.5; + i_embedded_c->apply(std::vector<DataVariant>{x}); + REQUIRE(y == 1.5); + REQUIRE(i_embedded_c->numberOfParameters() == 1); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1); + + REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::void_t); + + REQUIRE_THROWS_WITH(i_embedded_c->apply({std::vector<EmbeddedData>{}}), + "unexpected error: unexpected argument types while casting \"" + + demangle<std::vector<EmbeddedData>>() + "\" to \"" + demangle<double>() + '"'); + } + + SECTION("EmbeddedData(double, double) BuiltinFunctionEmbedder") + { + std::function sum = [&](double x, double y) -> std::shared_ptr<const double> { + return std::make_shared<const double>(x + y); + }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = + std::make_unique<BuiltinFunctionEmbedder<std::shared_ptr<const double>(double, double)>>(sum); + + // using 4ul enforces cast test + REQUIRE(i_embedded_c->numberOfParameters() == 2); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 2); + REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::double_t); + REQUIRE(i_embedded_c->getParameterDataTypes()[1] == ASTNodeDataType::double_t); + + REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<std::shared_ptr<const double>>); + + DataVariant result = i_embedded_c->apply(std::vector<DataVariant>{2.3, 4ul}); + EmbeddedData embedded_data = std::get<EmbeddedData>(result); + + const IDataHandler& handled_data = embedded_data.get(); + const DataHandler<const double>& data = dynamic_cast<const DataHandler<const double>&>(handled_data); + REQUIRE(*data.data_ptr() == (2.3 + 4ul)); + } + + SECTION("double(std::shared_ptr<double>) BuiltinFunctionEmbedder") + { + std::function abs = [&](std::shared_ptr<const double> x) -> double { return std::abs(*x); }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = + std::make_unique<BuiltinFunctionEmbedder<double(std::shared_ptr<const double>)>>(abs); + + REQUIRE(i_embedded_c->numberOfParameters() == 1); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1); + REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ast_node_data_type_from<std::shared_ptr<const double>>); + REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::double_t); + + EmbeddedData data(std::make_shared<DataHandler<const double>>(std::make_shared<const double>(-2.3))); + DataVariant result = i_embedded_c->apply({data}); + + REQUIRE(std::get<double>(result) == 2.3); + + REQUIRE_THROWS_WITH(i_embedded_c->apply({2.3}), + "unexpected error: unexpected argument types while casting: expecting EmbeddedData"); + + EmbeddedData wrong_embedded_data_type( + std::make_shared<DataHandler<const TinyVector<2>>>(std::make_shared<const TinyVector<2>>(-2, -2))); + REQUIRE_THROWS_WITH(i_embedded_c->apply({wrong_embedded_data_type}), + "unexpected error: unexpected argument types while casting: " + "invalid EmbeddedData type, expecting " + + demangle<DataHandler<const double>>()); + } + + SECTION("uint64_t(std::vector<uint64_t>) BuiltinFunctionEmbedder") + { + std::function sum = [&](const std::vector<uint64_t>& x) -> uint64_t { + uint64_t sum = 0; + for (size_t i = 0; i < x.size(); ++i) { + sum += x[i]; + } + return sum; + }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = + std::make_unique<BuiltinFunctionEmbedder<uint64_t(const std::vector<uint64_t>&)>>(sum); + + REQUIRE(i_embedded_c->numberOfParameters() == 1); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1); + REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t); + REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::unsigned_int_t); + + REQUIRE(std::get<uint64_t>(i_embedded_c->apply({std::vector{1ul, 2ul, 3ul}})) == 6); + REQUIRE(std::get<uint64_t>(i_embedded_c->apply({std::vector{1ul, 2ul, 3ul, 4ul}})) == 10); + + REQUIRE_THROWS_WITH(i_embedded_c->apply({std::vector{1.2, 2.3, 3.1, 4.4}}), + "unexpected error: unexpected argument types while casting \"" + + demangle<std::vector<double>>() + "\" to \"" + demangle<std::vector<uint64_t>>() + '"'); + + REQUIRE_THROWS_WITH(i_embedded_c->apply({std::vector<EmbeddedData>{}}), + "unexpected error: unexpected argument types while casting \"" + + demangle<std::vector<EmbeddedData>>() + "\" to \"" + demangle<std::vector<uint64_t>>() + '"'); + } + + SECTION("uint64_t(std::vector<EmbeddedData>) BuiltinFunctionEmbedder") + { + std::function sum = [&](const std::vector<std::shared_ptr<uint64_t>>& x) -> uint64_t { + uint64_t sum = 0; + for (size_t i = 0; i < x.size(); ++i) { + sum += *x[i]; + } + return sum; + }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = + std::make_unique<BuiltinFunctionEmbedder<uint64_t(const std::vector<std::shared_ptr<uint64_t>>&)>>(sum); + + REQUIRE(i_embedded_c->numberOfParameters() == 1); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1); + REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t); + REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::unsigned_int_t); + + std::vector<EmbeddedData> embedded_data; + REQUIRE(std::get<uint64_t>(i_embedded_c->apply({embedded_data})) == 0); + embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(1))); + embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(2))); + embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(3))); + + REQUIRE(std::get<uint64_t>(i_embedded_c->apply({embedded_data})) == 6); + + embedded_data.emplace_back(std::make_shared<DataHandler<double>>(std::make_shared<double>(4))); + REQUIRE_THROWS_WITH(i_embedded_c->apply({embedded_data}), + "unexpected error: unexpected argument types while casting: invalid" + " EmbeddedData type, expecting " + + demangle<DataHandler<uint64_t>>()); + + REQUIRE_THROWS_WITH(i_embedded_c->apply({TinyVector<1>{13}}), + "unexpected error: unexpected argument types while casting \"" + demangle<TinyVector<1>>() + + "\" to \"" + demangle<std::vector<std::shared_ptr<uint64_t>>>() + '"'); + } + + SECTION("double(void) BuiltinFunctionEmbedder") + { + std::function c = [](void) -> double { return 1.5; }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = std::make_unique<BuiltinFunctionEmbedder<double(void)>>(c); + + REQUIRE(1.5 == c()); + REQUIRE(std::get<double>(i_embedded_c->apply(std::vector<DataVariant>{})) == c()); + REQUIRE(i_embedded_c->numberOfParameters() == 0); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 0); + + REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::double_t); + } + + SECTION("void(void) BuiltinFunctionEmbedder") + { + std::function c = [](void) -> void {}; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = std::make_unique<BuiltinFunctionEmbedder<void(void)>>(c); + + REQUIRE_NOTHROW(std::get<std::monostate>(i_embedded_c->apply(std::vector<DataVariant>{}))); + REQUIRE(i_embedded_c->numberOfParameters() == 0); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 0); + + REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::void_t); + } + + SECTION("EmbeddedData(void) BuiltinFunctionEmbedder") + { + std::function c = [](void) -> std::shared_ptr<double> { return std::make_shared<double>(1.5); }; + + std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = + std::make_unique<BuiltinFunctionEmbedder<std::shared_ptr<double>(void)>>(c); + + REQUIRE(i_embedded_c->numberOfParameters() == 0); + REQUIRE(i_embedded_c->getParameterDataTypes().size() == 0); + + REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<std::shared_ptr<double>>); + + const auto embedded_data = std::get<EmbeddedData>(i_embedded_c->apply(std::vector<DataVariant>{})); + const IDataHandler& handled_data = embedded_data.get(); + const DataHandler<double>& data = dynamic_cast<const DataHandler<double>&>(handled_data); + REQUIRE(*data.data_ptr() == 1.5); + } + + SECTION("error") + { + std::function positive = [](double x) -> bool { return x >= 0; }; + + BuiltinFunctionEmbedder<bool(double)> embedded_positive{positive}; + + std::string arg = std::string{"2.3"}; + + std::vector<DataVariant> args; + args.push_back(arg); + + REQUIRE_THROWS(embedded_positive.apply(args)); + } +} diff --git a/tests/test_BuiltinFunctionEmbedderTable.cpp b/tests/test_BuiltinFunctionEmbedderTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cc254f190a07c6162053ea522627ac0eeb49586 --- /dev/null +++ b/tests/test_BuiltinFunctionEmbedderTable.cpp @@ -0,0 +1,42 @@ +#include <catch2/catch.hpp> + +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/EmbedderTable.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("BuiltinFunctionEmbedderTable", "[language]") +{ + rang::setControlMode(rang::control::Off); + + EmbedderTable<IBuiltinFunctionEmbedder> table; + + REQUIRE(table.size() == 0); + + std::shared_ptr<IBuiltinFunctionEmbedder> embedded_sin = + std::make_shared<BuiltinFunctionEmbedder<double(double)>>([](double x) -> double { return std::sin(x); }); + table.add(embedded_sin); + + REQUIRE(table.size() == 1); + + std::shared_ptr<IBuiltinFunctionEmbedder> embedded_greater = + std::make_shared<BuiltinFunctionEmbedder<bool(int, int)>>([](int i, int j) -> bool { return i > j; }); + table.add(embedded_greater); + + REQUIRE(table.size() == 2); + + REQUIRE(table[0] == embedded_sin); + REQUIRE(table[1] == embedded_greater); + + const auto& const_table = table; + + REQUIRE(const_table.size() == 2); + + REQUIRE(const_table[0] == embedded_sin); + REQUIRE(const_table[1] == embedded_greater); + +#ifndef NDEBUG + REQUIRE_THROWS_AS(table[2], AssertError); + REQUIRE_THROWS_AS(const_table[2], AssertError); +#endif // NDEBUG +} diff --git a/tests/test_BuiltinFunctionProcessor.cpp b/tests/test_BuiltinFunctionProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2a690a19fedb243b36fe23d88c0aa9b04079f5c --- /dev/null +++ b/tests/test_BuiltinFunctionProcessor.cpp @@ -0,0 +1,304 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/modules/MathModule.hpp> + +#include <test_BuiltinFunctionRegister.hpp> + +#define CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + using namespace Catch::Matchers; \ + \ + REQUIRE_THAT(found, Predicate<bool>([](bool found) -> bool { return found; }, \ + std::string{"Cannot find symbol '"} + variable_name + "'")); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_AST_THROWS_WITH(data, expected_error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + test_only::test_BuiltinFunctionRegister{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + \ + REQUIRE_THROWS_WITH(ast->execute(exec_policy), Catch::Matchers::Contains(expected_error)); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("BuiltinFunctionProcessor", "[language]") +{ + SECTION("math module functions") + { + // @note HERE we do not use SECTION to be able to count tests and to check + // that all math functions are actually tested + + std::set<std::string> tested_function_set; + { // sqrt + tested_function_set.insert("sqrt"); + std::string_view data = R"( +import math; +let x:R, x = sqrt(4); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::sqrt(4l)}); + } + + { // abs + tested_function_set.insert("abs"); + std::string_view data = R"( +import math; +let x:R, x = abs(-3.4); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::abs(-3.4)}); + } + + { // sin + tested_function_set.insert("sin"); + std::string_view data = R"( +import math; +let x:R, x = sin(1.3); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::sin(1.3)}); + } + + { // cos + tested_function_set.insert("cos"); + std::string_view data = R"( +import math; +let x:R, x = cos(1.3); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::cos(1.3)}); + } + + { // tan + tested_function_set.insert("tan"); + std::string_view data = R"( +import math; +let x:R, x = tan(1.3); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::tan(1.3)}); + } + + { // asin + tested_function_set.insert("asin"); + std::string_view data = R"( +import math; +let x:R, x = asin(0.7); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::asin(0.7)}); + } + + { // acos + tested_function_set.insert("acos"); + std::string_view data = R"( +import math; +let x:R, x = acos(0.7); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::acos(0.7)}); + } + + { // atan + tested_function_set.insert("atan"); + std::string_view data = R"( +import math; +let x:R, x = atan(0.7); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::atan(0.7)}); + } + + { // atan2 + tested_function_set.insert("atan2"); + std::string_view data = R"( +import math; +let x:R, x = atan2(0.7, 0.4); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::atan2(0.7, 0.4)}); + } + + { // sinh + tested_function_set.insert("sinh"); + std::string_view data = R"( +import math; +let x:R, x = sinh(0.6); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::sinh(0.6)}); + } + + { // cosh + tested_function_set.insert("cosh"); + std::string_view data = R"( +import math; +let x:R, x = cosh(1.7); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::cosh(1.7)}); + } + + { // tanh + tested_function_set.insert("tanh"); + std::string_view data = R"( +import math; +let x:R, x = tanh(0.6); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::tanh(0.6)}); + } + + { // asinh + tested_function_set.insert("asinh"); + std::string_view data = R"( +import math; +let x:R, x = asinh(0.6); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::asinh(0.6)}); + } + + { // acosh + tested_function_set.insert("acosh"); + std::string_view data = R"( +import math; +let x:R, x = acosh(1.7); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::acosh(1.7)}); + } + + { // tanh + tested_function_set.insert("atanh"); + std::string_view data = R"( +import math; +let x:R, x = atanh(0.6); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::atanh(0.6)}); + } + + { // exp + tested_function_set.insert("exp"); + std::string_view data = R"( +import math; +let x:R, x = exp(1.7); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::exp(1.7)}); + } + + { // log + tested_function_set.insert("log"); + std::string_view data = R"( +import math; +let x:R, x = log(1.6); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::log(1.6)}); + } + + { // pow + tested_function_set.insert("pow"); + std::string_view data = R"( +import math; +let x:R, x = pow(1.6, 2.3); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "x", double{std::pow(1.6, 2.3)}); + } + + { // ceil + tested_function_set.insert("ceil"); + std::string_view data = R"( +import math; +let z:Z, z = ceil(-1.2); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "z", int64_t{-1}); + } + + { // floor + tested_function_set.insert("floor"); + std::string_view data = R"( +import math; +let z:Z, z = floor(-1.2); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "z", int64_t{-2}); + } + + { // trunc + tested_function_set.insert("trunc"); + std::string_view data = R"( +import math; +let z:Z, z = trunc(-0.2) + trunc(0.7); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "z", int64_t{0}); + } + + { // round + tested_function_set.insert("round"); + std::string_view data = R"( +import math; +let z:Z, z = round(-1.2); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "z", int64_t{-1}); + } + + MathModule math_module; + + bool missing_test = false; + for (const auto& [function_name, builtin_function] : math_module.getNameBuiltinFunctionMap()) { + if (tested_function_set.find(function_name) == tested_function_set.end()) { + UNSCOPED_INFO("function '" << function_name << "' is NOT tested"); + missing_test = true; + } + } + REQUIRE_FALSE(missing_test); + + SECTION("catch runtime error") + { + std::string_view data = R"( +runtimeError(); +)"; + + std::string error = "runtime error"; + + CHECK_AST_THROWS_WITH(data, error); + } + } +} diff --git a/tests/test_BuiltinFunctionRegister.hpp b/tests/test_BuiltinFunctionRegister.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fdf46213388b23e46c1457a56ea213cf17ac83f0 --- /dev/null +++ b/tests/test_BuiltinFunctionRegister.hpp @@ -0,0 +1,178 @@ +#ifndef TEST_BUILTIN_FUNCTION_REGISTER_H +#define TEST_BUILTIN_FUNCTION_REGISTER_H + +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/TypeDescriptor.hpp> +#include <utils/Exceptions.hpp> + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t, + "builtin_t"}; +const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>; + +namespace test_only +{ +class test_BuiltinFunctionRegister +{ + private: + std::unordered_map<std::string, std::shared_ptr<IBuiltinFunctionEmbedder>> m_name_builtin_function_map; + + void + _populateNameBuiltinFunctionMap() + { + m_name_builtin_function_map.insert( + std::make_pair("runtimeError", std::make_shared<BuiltinFunctionEmbedder<void(void)>>( + [](void) -> void { throw NormalError("runtime error"); }))); + + m_name_builtin_function_map.insert(std::make_pair("RtoR", std::make_shared<BuiltinFunctionEmbedder<double(double)>>( + [](double x) -> double { return x + 1; }))); + + m_name_builtin_function_map.insert( + std::make_pair("ZtoR", std::make_shared<BuiltinFunctionEmbedder<double(int64_t)>>( + [](int64_t z) -> double { return 0.5 * z; }))); + + m_name_builtin_function_map.insert( + std::make_pair("NtoR", std::make_shared<BuiltinFunctionEmbedder<double(uint64_t)>>( + [](uint64_t n) -> double { return 0.5 * n; }))); + + m_name_builtin_function_map.insert(std::make_pair("BtoR", std::make_shared<BuiltinFunctionEmbedder<double(bool)>>( + [](bool b) -> double { return b; }))); + + m_name_builtin_function_map.insert( + std::make_pair("RRtoB", std::make_shared<BuiltinFunctionEmbedder<bool(double, double)>>( + [](double x, double y) -> bool { return x > y; }))); + + m_name_builtin_function_map.insert( + std::make_pair("StoB", std::make_shared<BuiltinFunctionEmbedder<bool(std::string)>>( + [](const std::string& s) -> bool { return s.size() > 0; }))); + + m_name_builtin_function_map.insert( + std::make_pair("RtoR1", std::make_shared<BuiltinFunctionEmbedder<TinyVector<1>(double)>>( + [](double r) -> TinyVector<1> { return {r}; }))); + + m_name_builtin_function_map.insert( + std::make_pair("R1toR", std::make_shared<BuiltinFunctionEmbedder<double(TinyVector<1>)>>( + [](TinyVector<1> x) -> double { return x[0]; }))); + + m_name_builtin_function_map.insert( + std::make_pair("R2toR", std::make_shared<BuiltinFunctionEmbedder<double(TinyVector<2>)>>( + [](TinyVector<2> x) -> double { return x[0] + x[1]; }))); + + m_name_builtin_function_map.insert( + std::make_pair("R3toR", std::make_shared<BuiltinFunctionEmbedder<double(const TinyVector<3>&)>>( + [](const TinyVector<3>& x) -> double { return x[0] + x[1] + x[2]; }))); + + m_name_builtin_function_map.insert( + std::make_pair("R3R2toR", + std::make_shared<BuiltinFunctionEmbedder<double(TinyVector<3>, TinyVector<2>)>>( + [](TinyVector<3> x, TinyVector<2> y) -> double { return x[0] * y[1] + (y[0] - x[2]) * x[1]; }))); + + m_name_builtin_function_map.insert( + std::make_pair("fidToR", std::make_shared<BuiltinFunctionEmbedder<double(const FunctionSymbolId&)>>( + [](const FunctionSymbolId&) -> double { return 0; }))); + + m_name_builtin_function_map.insert( + std::make_pair("builtinToBuiltin", + std::make_shared< + BuiltinFunctionEmbedder<std::shared_ptr<const double>(std::shared_ptr<const double>)>>( + [](std::shared_ptr<const double> x) -> std::shared_ptr<const double> { return x; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_BtoR", std::make_shared<BuiltinFunctionEmbedder<double(std::vector<bool>)>>( + [](const std::vector<bool>&) -> double { return 0.5; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_NtoR", std::make_shared<BuiltinFunctionEmbedder<double(std::vector<uint64_t>)>>( + [](const std::vector<uint64_t>&) -> double { return 0.5; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_ZtoR", std::make_shared<BuiltinFunctionEmbedder<double(std::vector<int64_t>)>>( + [](const std::vector<int64_t>&) -> double { return 0.5; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_RtoB", std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<double>)>>( + [](const std::vector<double>&) -> bool { return false; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_stringtoB", std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<std::string>)>>( + [](const std::vector<std::string>&) -> bool { return true; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_builtinToB", + std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<std::shared_ptr<const double>>)>>( + [](const std::vector<std::shared_ptr<const double>>&) -> bool { return true; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_R1ToR", + std::make_shared<BuiltinFunctionEmbedder<double(const std::vector<TinyVector<1>>&)>>( + [](const std::vector<TinyVector<1>>&) -> double { return 1; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_R2ToR", + std::make_shared<BuiltinFunctionEmbedder<double(const std::vector<TinyVector<2>>&)>>( + [](const std::vector<TinyVector<2>>&) -> double { return 1; }))); + + m_name_builtin_function_map.insert( + std::make_pair("tuple_R3ToR", std::make_shared<BuiltinFunctionEmbedder<double(const std::vector<TinyVector<3>>)>>( + [](const std::vector<TinyVector<3>>&) -> double { return 0; }))); + } + + void + _addBuiltinTypeAndVariables(ASTNode& ast) + { + SymbolTable& symbol_table = *ast.m_symbol_table; + auto [i_symbol, success] = symbol_table.add(builtin_data_type.nameOfTypeId(), ast.begin()); + if (not success) { + throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing"); + } + + i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t); + i_symbol->attributes().setIsInitialized(); + i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size(); + symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); + + auto [i_symbol_a, success_a] = symbol_table.add("a", ast.begin()); + if (not success_a) { + throw UnexpectedError("cannot add 'a' of type builtin_t for testing"); + } + i_symbol_a->attributes().setDataType(ast_node_data_type_from<std::shared_ptr<const double>>); + i_symbol_a->attributes().setIsInitialized(); + auto [i_symbol_b, success_b] = symbol_table.add("b", ast.begin()); + if (not success_b) { + throw UnexpectedError("cannot add 'b' of type builtin_t for testing"); + } + i_symbol_b->attributes().setDataType(ast_node_data_type_from<std::shared_ptr<const double>>); + i_symbol_b->attributes().setIsInitialized(); + } + + public: + test_BuiltinFunctionRegister(ASTNode& root_node) + { + SymbolTable& symbol_table = *root_node.m_symbol_table; + + auto& builtin_function_embedder_table = symbol_table.builtinFunctionEmbedderTable(); + + this->_populateNameBuiltinFunctionMap(); + this->_addBuiltinTypeAndVariables(root_node); + + for (const auto& [symbol_name, builtin_function] : m_name_builtin_function_map) { + auto [i_symbol, success] = symbol_table.add(symbol_name, root_node.begin()); + + if (not success) { + std::ostringstream error_message; + error_message << "cannot add symbol '" << symbol_name << "' it is already defined"; + throw parse_error(error_message.str(), root_node.begin()); + } + + i_symbol->attributes().setDataType(ASTNodeDataType::builtin_function_t); + i_symbol->attributes().setIsInitialized(); + i_symbol->attributes().value() = builtin_function_embedder_table.size(); + + builtin_function_embedder_table.add(builtin_function); + } + } +}; +} // namespace test_only + +#endif /* TEST_BUILTIN_FUNCTION_REGISTER_H */ diff --git a/tests/test_ConcatExpressionProcessor.cpp b/tests/test_ConcatExpressionProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..adc5f49e0360b2e1ea3e784ea83fae60cd157d69 --- /dev/null +++ b/tests/test_ConcatExpressionProcessor.cpp @@ -0,0 +1,74 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_CONCAT_EXPRESSION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ConcatExpressionProcessor", "[language]") +{ + SECTION("string + string") + { + CHECK_CONCAT_EXPRESSION_RESULT(R"(let s:string, s = "foo"; s = s+"bar";)", "s", std::string{"foobar"}); + } + + SECTION("string + N") + { + CHECK_CONCAT_EXPRESSION_RESULT(R"(let n:N, n = 1; let s:string, s = "foo_"; s = s+n;)", "s", std::string{"foo_1"}); + } + + SECTION("string + Z") + { + CHECK_CONCAT_EXPRESSION_RESULT(R"(let s:string, s = "foo_"; s = s+2;)", "s", std::string{"foo_2"}); + } + + SECTION("string + R") + { + CHECK_CONCAT_EXPRESSION_RESULT(R"(let s:string, s = "foo_"; s = s+2.4;)", "s", + std::string{"foo_"} + std::to_string(2.4)); + } + + SECTION("string + B") + { + CHECK_CONCAT_EXPRESSION_RESULT(R"(let s:string, s = "foo_"; s = s+true;)", "s", std::string{"foo_1"}); + } +} diff --git a/tests/test_ContinueProcessor.cpp b/tests/test_ContinueProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d4348b4558eaba1e7503601c4ee67bcbfa9ab00 --- /dev/null +++ b/tests/test_ContinueProcessor.cpp @@ -0,0 +1,22 @@ +#include <catch2/catch.hpp> + +#include <language/node_processor/ContinueProcessor.hpp> + +#include <rang.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ContinueProcessor", "[language]") +{ + rang::setControlMode(rang::control::Off); + + ExecutionPolicy exec_policy; + + REQUIRE(exec_policy.exec() == true); + + ContinueProcessor continue_processor; + continue_processor.execute(exec_policy); + + REQUIRE(exec_policy.exec() == false); + REQUIRE(exec_policy.jumpType() == ExecutionPolicy::JumpType::continue_jump); +} diff --git a/tests/test_DataVariant.cpp b/tests/test_DataVariant.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1fa8cf72be599782c25fd88f22613e465df818e8 --- /dev/null +++ b/tests/test_DataVariant.cpp @@ -0,0 +1,52 @@ +#include <catch2/catch.hpp> + +#include <language/utils/DataVariant.hpp> + +#include <sstream> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("DataVariant", "[language]") +{ + SECTION("AggregateDataVariant") + { + AggregateDataVariant aggregate{std::vector<DataVariant>{double{1.3}, int64_t{-3}, std::vector<double>{1, 2.7}}}; + + SECTION("size") + { + REQUIRE(aggregate.size() == 3); + } + + SECTION("output") + { + std::stringstream aggregate_output; + aggregate_output << aggregate; + + std::stringstream expected_output; + expected_output << '(' << double{1.3} << ", " << int64_t{-3} << ", (" << 1 << ", " << 2.7 << "))"; + REQUIRE(aggregate_output.str() == expected_output.str()); + } + + SECTION("values") + { + REQUIRE(std::get<double>(aggregate[0]) == double{1.3}); + REQUIRE(std::get<int64_t>(aggregate[1]) == int64_t{-3}); + REQUIRE(std::get<std::vector<double>>(aggregate[2]) == std::vector<double>{1, 2.7}); + } + + SECTION("Copy") + { + AggregateDataVariant aggregate_copy{aggregate}; + + REQUIRE(aggregate.size() == aggregate_copy.size()); + + for (size_t i = 0; i < aggregate.size(); ++i) { + REQUIRE(aggregate[i].index() == aggregate_copy[i].index()); + } + + REQUIRE(std::get<double>(aggregate[0]) == std::get<double>(aggregate_copy[0])); + REQUIRE(std::get<int64_t>(aggregate[1]) == std::get<int64_t>(aggregate_copy[1])); + REQUIRE(std::get<std::vector<double>>(aggregate[2]) == std::get<std::vector<double>>(aggregate_copy[2])); + } + } +} diff --git a/tests/test_DoWhileProcessor.cpp b/tests/test_DoWhileProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8f88a19aadf6236bc97e32e31518ea10d139a14 --- /dev/null +++ b/tests/test_DoWhileProcessor.cpp @@ -0,0 +1,112 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_WHILE_PROCESSOR_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_DO_WHILE_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("DoWhileProcessor", "[language]") +{ + SECTION("simple loop") + { + std::string_view data = R"( +let i:N, i = 3; +let j:N, j = 0; +do { + j++; + i += j; +} while(i<10); +)"; + CHECK_WHILE_PROCESSOR_RESULT(data, "i", 13ul); + } + + SECTION("do-while with break") + { + std::string_view data = R"( +let i:N, i = 3; +let j:N, j = 0; +do { + j++; + if (j==2) break; + i += j; +} while(i<10); +)"; + CHECK_WHILE_PROCESSOR_RESULT(data, "i", 4ul); + } + + SECTION("do-while with continue") + { + std::string_view data = R"( +let i:N, i = 3; +let j:N, j = 0; +do { + j++; + if (j<=3) continue; + i += j; +} while(i<10); +)"; + CHECK_WHILE_PROCESSOR_RESULT(data, "i", 12ul); + } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +do { +} while(1); +)"; + + CHECK_DO_WHILE_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: Z -> B"); + } + } +} diff --git a/tests/test_EmbeddedData.cpp b/tests/test_EmbeddedData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63ca0d42705bed2cbe85e1697f32e443e20303e9 --- /dev/null +++ b/tests/test_EmbeddedData.cpp @@ -0,0 +1,31 @@ +#include <catch2/catch.hpp> + +#include <language/utils/DataHandler.hpp> +#include <language/utils/EmbeddedData.hpp> + +#include <sstream> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("EmbeddedData", "[language]") +{ + REQUIRE_NOTHROW(EmbeddedData{}); + EmbeddedData e; + { + EmbeddedData f{std::make_shared<DataHandler<double>>(std::make_shared<double>(1.3))}; + REQUIRE_NOTHROW(e = std::move(f)); + } + + REQUIRE(*dynamic_cast<const DataHandler<double>&>(e.get()).data_ptr() == 1.3); + + { + EmbeddedData f{std::make_shared<DataHandler<double>>(std::make_shared<double>(2.3))}; + REQUIRE_NOTHROW(e = f); + } + + REQUIRE(*dynamic_cast<const DataHandler<double>&>(e.get()).data_ptr() == 2.3); + + std::ostringstream fout; + fout << e; + REQUIRE(fout.str() == "embedded_data"); +} diff --git a/tests/test_ExecutionPolicy.cpp b/tests/test_ExecutionPolicy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b293a64689492f7a85df579d0ac2af5df65a83f1 --- /dev/null +++ b/tests/test_ExecutionPolicy.cpp @@ -0,0 +1,44 @@ +#include <catch2/catch.hpp> + +#include <language/node_processor/ExecutionPolicy.hpp> + +#include <rang.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ExecutionPolicy", "[language]") +{ + rang::setControlMode(rang::control::Off); + + ExecutionPolicy exec_policy; + SECTION("no jump") + { + exec_policy = ExecutionPolicy{ExecutionPolicy{}, ExecutionPolicy::JumpType::no_jump}; + REQUIRE(exec_policy.exec() == true); + REQUIRE(exec_policy.jumpType() == ExecutionPolicy::JumpType::no_jump); + } + + SECTION("break jump") + { + exec_policy = ExecutionPolicy{ExecutionPolicy{}, ExecutionPolicy::JumpType::break_jump}; + REQUIRE(exec_policy.exec() == false); + REQUIRE(exec_policy.jumpType() == ExecutionPolicy::JumpType::break_jump); + } + + SECTION("continue jump") + { + exec_policy = ExecutionPolicy{ExecutionPolicy{}, ExecutionPolicy::JumpType::continue_jump}; + REQUIRE(exec_policy.exec() == false); + REQUIRE(exec_policy.jumpType() == ExecutionPolicy::JumpType::continue_jump); + } + + SECTION("context") + { + ExecutionPolicy::Context::SharedValues shared_values; + + exec_policy = ExecutionPolicy{ExecutionPolicy{}, ExecutionPolicy::Context{1, shared_values}}; + + REQUIRE(exec_policy.contextOfId(1).id() == 1); + REQUIRE_THROWS_WITH(exec_policy.contextOfId(2).id(), std::string{"unable to find context"}); + } +} diff --git a/tests/test_FakeProcessor.cpp b/tests/test_FakeProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd5031db5049eac005ee921a45253ca833935b1a --- /dev/null +++ b/tests/test_FakeProcessor.cpp @@ -0,0 +1,19 @@ +#include <catch2/catch.hpp> + +#include <language/node_processor/FakeProcessor.hpp> +#include <utils/Demangle.hpp> + +#include <rang.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("FakeProcessor", "[language]") +{ + rang::setControlMode(rang::control::Off); + + FakeProcessor fake_processor; + REQUIRE(fake_processor.typeIdName() == demangle<FakeProcessor>()); + + ExecutionPolicy exec_policy; + REQUIRE_NOTHROW(fake_processor.execute(exec_policy)); +} diff --git a/tests/test_ForProcessor.cpp b/tests/test_ForProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31ec05abccbf27cb28c6f674d178b15b7709ba4a --- /dev/null +++ b/tests/test_ForProcessor.cpp @@ -0,0 +1,106 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_FOR_PROCESSOR_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_FOR_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ForProcessor", "[language]") +{ + SECTION("simple for") + { + std::string_view data = R"( +let i:N, i = 0; +for(let l:N, l=0; l<10; ++l) { + i += l; +} +)"; + CHECK_FOR_PROCESSOR_RESULT(data, "i", 45ul); + } + + SECTION("for with break") + { + std::string_view data = R"( +let i:N, i = 0; +for(let l:N, l=0; l<10; ++l) { + i += l; + if (i > 30) break; +} +)"; + CHECK_FOR_PROCESSOR_RESULT(data, "i", 36ul); + } + + SECTION("for with continue") + { + std::string_view data = R"( +let i:N, i = 0; +for(let l:N, l=0; l<10; ++l) { + if (l<3) continue; + i += l; +} +)"; + CHECK_FOR_PROCESSOR_RESULT(data, "i", 42ul); + } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +for(let l:N, l=0; l; ++l) { +} +)"; + + CHECK_FOR_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: N -> B"); + } + } +} diff --git a/tests/test_FunctionProcessor.cpp b/tests/test_FunctionProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59386bbae65a807841ead561899e0a61719a82d3 --- /dev/null +++ b/tests/test_FunctionProcessor.cpp @@ -0,0 +1,546 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_FUNCTION_EVALUATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("FunctionProcessor", "[language]") +{ + SECTION("Scalar functions") + { + SECTION("-> B") + { + SECTION("B -> B") + { + SECTION("from B") + { + std::string_view data = R"( +let f : B -> B, b -> not b; +let b:B, b = f(true); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + } + + SECTION("N -> B") + { + SECTION("from B") + { + std::string_view data = R"( +let f : N -> B, n -> n > 2; +let b:B, b = f(true); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + + SECTION("from N") + { + std::string_view data = R"( +let f : N -> B, n -> n > 2; +let n:N, n = 3; +let b:B, b = f(n); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", true); + } + + SECTION("from Z") + { + std::string_view data = R"( +let f : N -> B, (n) -> (n > 2); +let b:B, b = f(2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + } + + SECTION("Z -> B") + { + SECTION("from B") + { + std::string_view data = R"( +let f : Z -> B, z -> z-3 >= 0; +let b:B, b = f(true); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + + SECTION("from N") + { + std::string_view data = R"( +let f : Z -> B, z -> z-3 >= 0; +let n:N, n = 3; +let b:B, b = f(n); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", true); + } + + SECTION("from Z") + { + std::string_view data = R"( +let f : Z -> B, z -> (z-3 >= 0); +let b:B, b = f(2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + } + + SECTION("R -> B") + { + SECTION("from B") + { + std::string_view data = R"( +let f : R -> B, x -> x*x < 4; +let b:B, b = f(true); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", true); + } + + SECTION("from N") + { + std::string_view data = R"( +let f : R -> B, x -> x*x < 4; +let n:N, n = 3; +let b:B, b = f(n); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + + SECTION("from Z") + { + std::string_view data = R"( +let f : R -> B, x -> x*x < 4; +let b:B, b = f(-2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + + SECTION("from R") + { + std::string_view data = R"( +let f : R -> B, x -> x*x < 4; +let b:B, b = f(-1.3); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", true); + } + } + } + + SECTION("-> N") + { + SECTION("from N*N") + { + std::string_view data = R"( +let f : N*N -> N, (m,n) -> m*n; +let n:N, n = f(2,4); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "n", 8ul); + } + + SECTION("from Z*Z") + { + std::string_view data = R"( +let f : Z*Z -> N, (p,q) -> p*q; +let n:N, n = f(-2,-4); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "n", 8ul); + } + } + + SECTION("-> Z") + { + SECTION("from N*N") + { + std::string_view data = R"( +let f : N*N -> Z, (m,n) -> m*n; +let z:Z, z = f(2,4); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "z", 8l); + } + + SECTION("from Z*Z") + { + std::string_view data = R"( +let f : Z*Z -> Z, (p,q) -> p*q; +let z:Z, z = f(-2,4); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "z", -8l); + } + + SECTION("from R*Z") + { + std::string_view data = R"( +let f : R*Z -> R, (p,q) -> p*q; +let x:R, x = f(-0.5,8); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{-0.5 * 8l}); + } + } + + SECTION("-> R") + { + SECTION("from N*R") + { + std::string_view data = R"( +let f : N*R -> R, (n,x) -> n*x; +let r:R, r = f(2,4.2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "r", double{2ul * 4.2}); + } + + SECTION("from R") + { + std::string_view data = R"( +let f : R -> R, x -> x*x-1; +let r:R, r = f(4); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "r", double{15}); + } + + SECTION("from R using global variable") + { + std::string_view data = R"( +let x0:R, x0 = 3; +let f : R -> R, x -> x-x0; +let x:R, x = f(7.3); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{7.3 - 3}); + } + } + + SECTION("-> string") + { + SECTION("from string") + { + std::string_view data = R"( +let f : string -> string, s -> s+"bar"; +let s:string, s = f("foo"); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "s", std::string{"foobar"}); + } + + SECTION("from string*N") + { + std::string_view data = R"( +let f : string*N -> string, (s,n) -> s+n; +let s:string, s = f("id", 2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "s", std::string{"id2"}); + } + + SECTION("from string*N (with conversion)") + { + std::string_view data = R"( +let f : string*N -> string, (s,n) -> s+n; +let s:string, s = f(3, 2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "s", std::string{"32"}); + } + + SECTION("from N (with conversion)") + { + std::string_view data = R"( +let f : N -> string, n -> n; +let s:string, s = f(3); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "s", std::string{"3"}); + } + } + } + + SECTION("multi-expression functions") + { + SECTION(" -> N*R") + { + std::string_view data = R"( +let f : N -> N*R, n -> (2*n, 0.3*n); +let (n,x):N*R, (n,x) = f(2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "n", uint64_t{4}); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{0.3 * int64_t{2}}); + } + + SECTION(" -> N*R*B") + { + std::string_view data = R"( +let f : N -> N*R*B, n -> (2*n, 0.3*n, 1.4*n>n*n); +let (n,x,b):N*R*B, (n,x,b) = f(2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "n", uint64_t{4}); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{0.3 * int64_t{2}}); + CHECK_FUNCTION_EVALUATION_RESULT(data, "b", false); + } + } + + SECTION("multi-expression functions with flattening") + { + SECTION(" -> N*R") + { + std::string_view data = R"( +let f : N -> N, n -> 2*n; +let (x,n):R*N, (x,n) = (2.3, f(3)); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "n", uint64_t{6}); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{2.3}); + } + + SECTION(" -> N*R*B") + { + std::string_view data = R"( +import math; + +let f : N -> N*R, n -> (2*n, 0.3*n); +let (n,x,s):N*R*R, (n,x,s) = (f(2), sin(1)); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "n", uint64_t{4}); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{0.3 * int64_t{2}}); + CHECK_FUNCTION_EVALUATION_RESULT(data, "s", double{std::sin(1)}); + } + } + + SECTION("R^d functions (single value)") + { + SECTION(" R^1 -> R^1") + { + std::string_view data = R"( +let f : R^1 -> R^1, x -> 2*x; +let x:R^1, x = 3; + +let fx:R^1, fx = f(x); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<1>{3})); + } + + SECTION(" R^2 -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> 2*x; +let x:R^2, x = (3, 7); + +let fx:R^2, fx = f(x); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<2>{3, 7})); + } + + SECTION(" R^3 -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R^3, x -> 2*x; +let x:R^3, x = (2, 4, 7); + +let fx:R^3, fx = f(x); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<3>{2, 4, 7})); + } + + SECTION(" R -> R^1") + { + std::string_view data = R"( +let f : R -> R^1, x -> 2*x; +let x:R, x = 3; + +let fx:R^1, fx = f(x); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<1>{3})); + } + + SECTION(" R*R -> R^2") + { + std::string_view data = R"( +let f : R*R -> R^2, (x,y) -> (2*x, 3*y); +let fx:R^2, fx = f(2, 3); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (TinyVector<2>{2 * 2, 3 * 3})); + } + + SECTION(" R -> R^3") + { + std::string_view data = R"( +let f : R -> R^3, x -> (x, 2*x, x*x); + +let fx:R^3, fx = f(3); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (TinyVector<3>{3, 6, 9})); + } + } + + SECTION("multi-expression functions (using R^d)") + { + SECTION(" R -> R*R^1*R^2*R^3") + { + std::string_view data = R"( +let f : R -> R*R^1*R^2*R^3, x -> (x+1, 2*x, (x-2, x+2), (1, 0.5*x, x*x)); + +let (x, x1, x2, x3):R*R^1*R^2*R^3, (x, x1, x2, x3) = f(3); +)"; + + const double x = 3; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", (double{x + 1})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x1", (TinyVector<1>{2 * x})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x2", (TinyVector<2>{x - 2, x + 2})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x3", (TinyVector<3>{1, 0.5 * x, x * x})); + } + + SECTION(" R^2*R^3 -> R*R^1*R^2*R^3") + { + std::string_view data = R"( +let f : R^2*R^3 -> R*R^1*R^2*R^3, + (x2, x3) -> (x2[0]+x3[2], x3[1], (x3[0], x2[1]), (x3[0], x3[0]+x2[1], x3[2])); + +let y2:R^2, y2 = (2.3, 4.1); +let y3:R^3, y3 = (1.2, 1.3, 2.1); +let(x, x1, x2, x3) : R*R^1*R^2*R^3, (x, x1, x2, x3) = f(y2, y3); +)"; + + TinyVector<2> y2{2.3, 4.1}; + TinyVector<3> y3{1.2, 1.3, 2.1}; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", (double{y2[0] + y3[2]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x1", (TinyVector<1>{y3[1]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x2", (TinyVector<2>{y3[0], y2[1]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x3", (TinyVector<3>{y3[0], y3[0] + y2[1], y3[2]})); + } + + SECTION(" R^2*R^3 -> R*R^1*R^2*R^3 [with 0 as argument]") + { + std::string_view data = R"( +let f : R^2*R^3 -> R*R^1*R^2*R^3, + (x2, x3) -> (x2[0]+x3[2], x3[1], (x3[0], x2[1]), (x3[0], x3[0]+x2[1], x3[2])); + +let y2:R^2, y2 = (2.3, 4.1); +let (x, x1, x2, x3) : R*R^1*R^2*R^3, (x, x1, x2, x3) = f(y2, 0); +)"; + + TinyVector<2> y2{2.3, 4.1}; + TinyVector<3> y3{zero}; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", (double{y2[0] + y3[2]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x1", (TinyVector<1>{y3[1]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x2", (TinyVector<2>{y3[0], y2[1]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x3", (TinyVector<3>{y3[0], y3[0] + y2[1], y3[2]})); + } + + SECTION(" R^2*R^3 -> R*R^1*R^2*R^3 [with 0 in result]") + { + std::string_view data = R"( +let f : R^2*R^3 -> R*R^1*R^2*R^3, + (x2, x3) -> (x2[0]+x3[2], x3[1], 0, 0); + +let y2:R^2, y2 = (2.3, 4.1); +let (x, x1, x2, x3):R*R^1*R^2*R^3, (x, x1, x2, x3) = f(y2, 0); +)"; + + TinyVector<2> y2{2.3, 4.1}; + TinyVector<3> y3{zero}; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", (double{y2[0] + y3[2]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x1", (TinyVector<1>{y3[1]})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x2", (TinyVector<2>{zero})); + CHECK_FUNCTION_EVALUATION_RESULT(data, "x3", (TinyVector<3>{zero})); + } + } + + SECTION("function composition") + { + SECTION("N -> N -> R") + { + std::string_view data = R"( +let f : N -> N, n -> 2*n; +let g : N -> R, n -> 2*n+0.5; + +let x:R, x = g(f(3)); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{(2 * 3) * 2 + 0.5}); + } + + SECTION("R -> R*R -> R") + { + std::string_view data = R"( +import math; +let f : N -> N, n -> 2*n; +let g : N -> R, n -> sin(2*n)+0.5; + +let x:R, x = g(f(3)); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{std::sin((2 * 3) * 2) + 0.5}); + } + + SECTION("R -> R*R -> R") + { + std::string_view data = R"( +import math; +let f : R -> R*R, x -> (x+1, x*2); + +let x:R, x = pow(f(2)); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{std::pow(2. + 1, 2. * 2)}); + } + + SECTION("R -> R^2 -> R") + { + std::string_view data = R"( +import math; +let f : R -> R^2, x -> (x+1, x*2); +let g : R^2 -> R, x -> x[0] + x[1]; + +let x:R, x = g(f(3)); +)"; + + double x0 = 3; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{x0 + 1 + x0 * 2}); + } + + SECTION("R -> R^2*R^3 -> R") + { + std::string_view data = R"( +import math; +let f : R -> R^2*R^3, x -> ((x+1, x*2), (6*x, 7-x, x/2.3)); +let g : R^2*R^3 -> R, (x, y) -> x[0]*x[1] + y[0]*y[1]-y[2]; + +let x:R, x = g(f(3)); +)"; + + double x0 = 3; + CHECK_FUNCTION_EVALUATION_RESULT(data, "x", double{(x0 + 1) * x0 * 2 + 6 * x0 * (7 - x0) - x0 / 2.3}); + } + } +} diff --git a/tests/test_FunctionSymbolId.cpp b/tests/test_FunctionSymbolId.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3213f86d1962d3d8726e20ce866d83d2b73f69b2 --- /dev/null +++ b/tests/test_FunctionSymbolId.cpp @@ -0,0 +1,56 @@ +#include <catch2/catch.hpp> + +#include <language/utils/FunctionSymbolId.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/PugsAssert.hpp> + +#include <sstream> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("FunctionSymbolId", "[language]") +{ + std::shared_ptr<SymbolTable> s = std::make_shared<SymbolTable>(); + const FunctionSymbolId f{2, s}; + REQUIRE(f.id() == 2); + REQUIRE(&f.symbolTable() == &(*s)); + + { + FunctionSymbolId g{f}; + REQUIRE(g.id() == 2); + } + + { + FunctionSymbolId h{4, s}; + FunctionSymbolId g{std::move(h)}; + + REQUIRE(g.id() == 4); + } + + { + FunctionSymbolId g; + g = f; + REQUIRE(g.id() == 2); + } + + { + FunctionSymbolId g; + FunctionSymbolId h{4, s}; + g = std::move(h); + REQUIRE(g.id() == 4); + } + + { + std::ostringstream sout; + sout << f; + + REQUIRE(sout.str() == "2"); + } + +#ifndef NDEBUG + { + std::shared_ptr<SymbolTable> unset_s; + REQUIRE_THROWS_AS((FunctionSymbolId{0, unset_s}.symbolTable()), AssertError); + } +#endif +} diff --git a/tests/test_FunctionTable.cpp b/tests/test_FunctionTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6ae9ab2f856457aaff70aaf2e35146661fde1b0 --- /dev/null +++ b/tests/test_FunctionTable.cpp @@ -0,0 +1,97 @@ +#include <catch2/catch.hpp> + +#include <language/utils/FunctionTable.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("FunctionTable", "[language]") +{ + rang::setControlMode(rang::control::Off); + + SECTION("FunctionDescriptor") + { + std::unique_ptr domain_mapping_node = std::make_unique<ASTNode>(); + domain_mapping_node->m_data_type = ASTNodeDataType::unsigned_int_t; + + std::unique_ptr definition_node = std::make_unique<ASTNode>(); + definition_node->m_data_type = ASTNodeDataType::double_t; + FunctionDescriptor f{"f", std::move(domain_mapping_node), std::move(definition_node)}; + + REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t); + REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t); + + REQUIRE(domain_mapping_node == nullptr); + REQUIRE(definition_node == nullptr); + } + +#ifndef NDEBUG + SECTION("uninitialized FunctionDescriptor") + { + std::unique_ptr domain_mapping_node = std::make_unique<ASTNode>(); + domain_mapping_node->m_data_type = ASTNodeDataType::unsigned_int_t; + + std::unique_ptr definition_node = std::make_unique<ASTNode>(); + definition_node->m_data_type = ASTNodeDataType::double_t; + + SECTION("nothing initialized") + { + FunctionDescriptor f{"function", nullptr, nullptr}; + REQUIRE_THROWS_AS(f.domainMappingNode(), AssertError); + REQUIRE_THROWS_AS(f.definitionNode(), AssertError); + } + + SECTION("domain mapping uninitialized") + { + FunctionDescriptor f{"function", nullptr, std::move(definition_node)}; + REQUIRE_THROWS_AS(f.domainMappingNode(), AssertError); + REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t); + REQUIRE(definition_node == nullptr); + } + + SECTION("definition node uninitialized") + { + FunctionDescriptor f{"function", std::move(domain_mapping_node), nullptr}; + REQUIRE_THROWS_AS(f.definitionNode(), AssertError); + REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t); + REQUIRE(domain_mapping_node == nullptr); + } + } +#endif // NDEBUG + + FunctionTable table; + + REQUIRE(table.size() == 0); + + std::unique_ptr domain_mapping_node = std::make_unique<ASTNode>(); + domain_mapping_node->m_data_type = ASTNodeDataType::unsigned_int_t; + + std::unique_ptr definition_node = std::make_unique<ASTNode>(); + definition_node->m_data_type = ASTNodeDataType::double_t; + + size_t function_id = + table.add(FunctionDescriptor{"function", std::move(domain_mapping_node), std::move(definition_node)}); + + REQUIRE(domain_mapping_node == nullptr); + REQUIRE(definition_node == nullptr); + + REQUIRE(function_id == 0); + REQUIRE(table.size() == 1); + + const auto& const_table = table; + REQUIRE(const_table.size() == 1); + + auto& f = table[function_id]; + REQUIRE(f.name() == "function"); + REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t); + REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t); + + const auto& const_f = const_table[function_id]; + REQUIRE(const_f.name() == "function"); + REQUIRE(const_f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t); + REQUIRE(const_f.definitionNode().m_data_type == ASTNodeDataType::double_t); + +#ifndef NDEBUG + REQUIRE_THROWS_AS(table[table.size()], AssertError); + REQUIRE_THROWS_AS(const_table[const_table.size()], AssertError); +#endif // NDEBUG +} diff --git a/tests/test_INodeProcessor.cpp b/tests/test_INodeProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1bbe63635edb9e1764656b2d7f55e76ffd0070f --- /dev/null +++ b/tests/test_INodeProcessor.cpp @@ -0,0 +1,19 @@ +#include <catch2/catch.hpp> + +#include <language/node_processor/FakeProcessor.hpp> +#include <utils/Demangle.hpp> + +#include <rang.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("INodeProcessor", "[language]") +{ + rang::setControlMode(rang::control::Off); + + std::unique_ptr<INodeProcessor> node_processor = std::make_unique<FakeProcessor>(); + REQUIRE(node_processor->typeIdName() == demangle<FakeProcessor>()); + + ExecutionPolicy exec_policy; + REQUIRE_NOTHROW(node_processor->execute(exec_policy)); +} diff --git a/tests/test_IfProcessor.cpp b/tests/test_IfProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ccade16253ae5b1024a97cc5ba038ec222bf5156 --- /dev/null +++ b/tests/test_IfProcessor.cpp @@ -0,0 +1,118 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_IF_PROCESSOR_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_IF_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("IfProcessor", "[language]") +{ + SECTION("simple if(true)") + { + std::string_view data = R"( +let i:N, i = 0; +if(true) { + i = 1; +} +)"; + CHECK_IF_PROCESSOR_RESULT(data, "i", 1ul); + } + + SECTION("simple if(false)") + { + std::string_view data = R"( +let i:N, i = 0; +if(false) { + i = 1; +} +)"; + CHECK_IF_PROCESSOR_RESULT(data, "i", 0ul); + } + + SECTION("simple if(true)else") + { + std::string_view data = R"( +let i:N, i = 0; +if(true) { + i = 1; +} else { + i = 2; +} +)"; + CHECK_IF_PROCESSOR_RESULT(data, "i", 1ul); + } + + SECTION("simple if(false)") + { + std::string_view data = R"( +let i:N, i = 0; +if(false) { + i = 1; +} else { + i = 2; +} +)"; + CHECK_IF_PROCESSOR_RESULT(data, "i", 2ul); + } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +if (1.2) { +} + +)"; + + CHECK_IF_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: R -> B"); + } + } +} diff --git a/tests/test_IncDecExpressionProcessor.cpp b/tests/test_IncDecExpressionProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca13dbde2c33330515300b1fa19ba163a771c5f2 --- /dev/null +++ b/tests/test_IncDecExpressionProcessor.cpp @@ -0,0 +1,130 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_INC_DEC_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("IncDecExpressionProcessor", "[language]") +{ + SECTION("pre ++") + { + SECTION("N") + { + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; ++n;)", "n", 3ul); + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; let m:N, m = ++n;)", "m", 3ul); + } + + SECTION("Z") + { + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; ++z;)", "z", 3l); + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; let p:Z, p = ++z;)", "p", 3l); + } + + SECTION("R") + { + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; ++r;)", "r", 3.); + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; let s:R, s = ++r;)", "s", 3.); + } + } + + SECTION("pre --") + { + SECTION("N") + { + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; --n;)", "n", 1ul); + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; let m:N, m = --n;)", "m", 1ul); + } + + SECTION("Z") + { + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; --z;)", "z", 1l); + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; let p:Z, p = --z;)", "p", 1l); + } + + SECTION("R") + { + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; --r;)", "r", 1.); + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; let s:R, s = --r;)", "s", 1.); + } + } + + SECTION("post ++") + { + SECTION("N") + { + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; n++;)", "n", 3ul); + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; let m:N, m = n++;)", "m", 2ul); + } + + SECTION("Z") + { + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; z++;)", "z", 3l); + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; let p:Z, p = z++;)", "p", 2l); + } + + SECTION("R") + { + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; r++;)", "r", 3.); + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; let s:R, s = r++;)", "s", 2.); + } + } + + SECTION("post --") + { + SECTION("N") + { + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; n--;)", "n", 1ul); + CHECK_INC_DEC_RESULT(R"(let n:N, n = 2; let m:N, m = n--;)", "m", 2ul); + } + + SECTION("Z") + { + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; z--;)", "z", 1l); + CHECK_INC_DEC_RESULT(R"(let z:Z, z = 2; let p:Z, p = z--;)", "p", 2l); + } + + SECTION("R") + { + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; r--;)", "r", 1.); + CHECK_INC_DEC_RESULT(R"(let r:R, r = 2; let s:R, s = r--;)", "s", 2.); + } + } +} diff --git a/tests/test_ListAffectationProcessor.cpp b/tests/test_ListAffectationProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0f17e7f593f98a15457686e9e38b0bccfa34938 --- /dev/null +++ b/tests/test_ListAffectationProcessor.cpp @@ -0,0 +1,124 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_AFFECTATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_AFFECTATION_THROWS(data) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + REQUIRE_THROWS(ASTNodeExpressionBuilder{*ast}, \ + Catch::Matchers::Contains("invalid operands to affectation expression")); \ + } + +#define CHECK_AFFECTATION_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ListAffectationProcessor", "[language]") +{ + SECTION("ListAffectations") + { + SECTION("R*R^2*string") + { + CHECK_AFFECTATION_RESULT(R"(let (x,u,s): R*R^2*string, (x,u,s) = (1.2, (2,3), "foo");)", "x", double{1.2}); + CHECK_AFFECTATION_RESULT(R"(let (x,u,s): R*R^2*string, (x,u,s) = (1.2, (2,3), "foo");)", "u", + (TinyVector<2>{2, 3})); + CHECK_AFFECTATION_RESULT(R"(let (x,u,s): R*R^2*string, (x,u,s) = (1.2, (2,3), "foo");)", "s", std::string{"foo"}); + } + + SECTION("compound with string conversion") + { + CHECK_AFFECTATION_RESULT(R"(let z:R, z = 3; let (x,u,s):R*R^2*string, (x,u,s) = (1.2, (2,3), z);)", "s", + std::to_string(double{3})); + { + std::ostringstream os; + os << TinyVector<1>{7} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let v:R^1, v = 7; let (x,u,s):R*R^2*string, (x,u,s) = (1.2, (2,3), v);)", "s", + os.str()); + } + { + std::ostringstream os; + os << TinyVector<2>{6, 3} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let v: R^2, v = (6,3); let (x,u,s):R*R^2*string, (x,u,s) = (1.2, (2,3), v);)", "s", + os.str()); + } + { + std::ostringstream os; + os << TinyVector<3>{1, 2, 3} << std::ends; + CHECK_AFFECTATION_RESULT(R"(let v:R^3, v = (1,2,3); let (x,u,s):R*R^2*string, (x,u,s) = (1.2, (2,3), v);)", "s", + os.str()); + } + } + + SECTION("compound R^d from '0'") + { + CHECK_AFFECTATION_RESULT(R"(let (x,y,z):R^3*R^2*R^1, (x,y,z) = (0,0,0);)", "x", (TinyVector<3>{zero})); + CHECK_AFFECTATION_RESULT(R"(let (x,y,z):R^3*R^2*R^1, (x,y,z) = (0,0,0);)", "y", (TinyVector<2>{zero})); + CHECK_AFFECTATION_RESULT(R"(let (x,y,z):R^3*R^2*R^1, (x,y,z) = (0,0,0);)", "z", (TinyVector<1>{zero})); + } + + SECTION("compound with subscript values") + { + CHECK_AFFECTATION_RESULT(R"(let x:R^3; (x[0], x[2], x[1]) = (4, 6, 5);)", "x", (TinyVector<3>{4, 5, 6})); + CHECK_AFFECTATION_RESULT(R"(let x:R^2; (x[1], x[0]) = (3, 6);)", "x", (TinyVector<2>{6, 3})); + CHECK_AFFECTATION_RESULT(R"(let x:R^1; let y:R; (y, x[0]) = (4, 2.3);)", "x", (TinyVector<1>{2.3})); + } + } +} diff --git a/tests/test_MathModule.cpp b/tests/test_MathModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..15cb845c48c90c525a06996a4065be8ff556c9c0 --- /dev/null +++ b/tests/test_MathModule.cpp @@ -0,0 +1,325 @@ +#include <catch2/catch.hpp> + +#include <language/modules/MathModule.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("MathModule", "[language]") +{ + rang::setControlMode(rang::control::Off); + + MathModule math_module; + const auto& name_builtin_function = math_module.getNameBuiltinFunctionMap(); + + REQUIRE(name_builtin_function.size() == 22); + + SECTION("double -> double") + { + double arg = 0.7; + + DataVariant arg_variant = arg; + + SECTION("sqrt") + { + auto i_function = name_builtin_function.find("sqrt"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::sqrt(arg); + + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("abs") + { + auto i_function = name_builtin_function.find("abs"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + { + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::abs(arg); + + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + { + arg = -3; + + DataVariant arg_variant = arg; + + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::abs(arg); + + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + } + + SECTION("sin") + { + auto i_function = name_builtin_function.find("sin"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::sin(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("cos") + { + auto i_function = name_builtin_function.find("cos"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::cos(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("tan") + { + auto i_function = name_builtin_function.find("tan"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::tan(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("asin") + { + auto i_function = name_builtin_function.find("asin"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::asin(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("acos") + { + auto i_function = name_builtin_function.find("acos"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::acos(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("atan") + { + auto i_function = name_builtin_function.find("atan"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::atan(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("sinh") + { + arg = 1.3; + arg_variant = arg; + + auto i_function = name_builtin_function.find("sinh"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::sinh(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("cosh") + { + auto i_function = name_builtin_function.find("cosh"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::cosh(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("tanh") + { + auto i_function = name_builtin_function.find("tanh"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::tanh(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("asinh") + { + auto i_function = name_builtin_function.find("asinh"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::asinh(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("acosh") + { + arg = 10; + arg_variant = arg; + + auto i_function = name_builtin_function.find("acosh"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::acosh(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("atanh") + { + auto i_function = name_builtin_function.find("atanh"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::atanh(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("exp") + { + auto i_function = name_builtin_function.find("exp"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::exp(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + + SECTION("log") + { + auto i_function = name_builtin_function.find("log"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + auto result = std::log(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + } + + SECTION("double -> int64_t") + { + double arg = 1.3; + + DataVariant arg_variant = arg; + + SECTION("ceil") + { + auto i_function = name_builtin_function.find("ceil"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + int64_t result = std::ceil(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == result); + } + + SECTION("floor") + { + auto i_function = name_builtin_function.find("floor"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + int64_t result = std::floor(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == result); + } + + SECTION("trunc") + { + auto i_function = name_builtin_function.find("trunc"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + int64_t result = std::trunc(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == result); + } + + SECTION("round") + { + auto i_function = name_builtin_function.find("round"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + int64_t result = std::lround(arg); + REQUIRE(std::get<decltype(result)>(result_variant) == result); + } + } + + SECTION("(double, double) -> double") + { + double arg0 = 3; + double arg1 = 2; + + DataVariant arg0_variant = arg0; + DataVariant arg1_variant = arg1; + + SECTION("atan2") + { + auto i_function = name_builtin_function.find("atan2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg0_variant, arg1_variant}); + + auto result = std::atan2(arg0, arg1); + REQUIRE(std::get<decltype(result)>(result_variant) == result); + } + + SECTION("pow") + { + auto i_function = name_builtin_function.find("pow"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg0_variant, arg1_variant}); + + auto result = std::pow(arg0, arg1); + REQUIRE(std::get<decltype(result)>(result_variant) == Approx(result)); + } + } +} diff --git a/tests/test_NameProcessor.cpp b/tests/test_NameProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84669c888673d8339fa2263130c7a480f57c1754 --- /dev/null +++ b/tests/test_NameProcessor.cpp @@ -0,0 +1,58 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/node_processor/NameProcessor.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("NameProcessor", "[language]") +{ + rang::setControlMode(rang::control::Off); + + std::string_view data = R"( +let n:N, n=3; +let m:N, m = n; +n = 2; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeDeclarationToAffectationConverter{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + + ASTNodeExpressionBuilder{*ast}; + ExecutionPolicy exec_policy; + ast->execute(exec_policy); + + auto symbol_table = ast->m_symbol_table; + + using namespace TAO_PEGTL_NAMESPACE; + position use_position{internal::iterator{"fixture"}, "fixture"}; + use_position.byte = 100; // after declarative position + auto symbol_n = symbol_table->find("n", use_position).first->attributes(); + auto value_n = std::get<long unsigned int>(symbol_n.value()); + + REQUIRE(value_n == 2); + + auto symbol_m = symbol_table->find("m", use_position).first->attributes(); + auto value_m = std::get<long unsigned int>(symbol_m.value()); + + REQUIRE(value_m == 3); + + REQUIRE(ast->children[0]->children[0]->m_node_processor->typeIdName() == demangle<NameProcessor>()); + REQUIRE(ast->children[1]->children[0]->m_node_processor->typeIdName() == demangle<NameProcessor>()); + REQUIRE(ast->children[1]->children[1]->m_node_processor->typeIdName() == demangle<NameProcessor>()); + REQUIRE(ast->children[2]->children[0]->m_node_processor->typeIdName() == demangle<NameProcessor>()); +} diff --git a/tests/test_OStreamProcessor.cpp b/tests/test_OStreamProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a88662b1a00f0dfaf4977da9a79b7d44dd2405f1 --- /dev/null +++ b/tests/test_OStreamProcessor.cpp @@ -0,0 +1,99 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/node_processor/OStreamProcessor.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +void +_replaceOStream(ASTNode& node, std::ostringstream& sout) +{ + if (node.is_type<language::cout_kw>() or node.is_type<language::cerr_kw>()) { + node.m_node_processor = std::make_unique<OStreamProcessor>(node, sout); + } else { + for (auto& child_node : node.children) { + _replaceOStream(*child_node, sout); + } + } +} + +#define CHECK_OSTREAM_EXPRESSION_RESULT(data, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + \ + std::ostringstream sout; \ + _replaceOStream(*ast, sout); \ + \ + ast->execute(exec_policy); \ + \ + REQUIRE(sout.str() == expected_value); \ + } + +#define CHECK_OSTREAM_EXPRESSION_THROWS(data, expected_error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert((std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view>) or \ + (std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>)); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_error); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("OStreamProcessor", "[language]") +{ + SECTION("cout") + { + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << 2;)", "2"); + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << true;)", "true"); + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << false;)", "false"); + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << "x=" << 2 << "\n";)", "x=2\n"); + } + + SECTION("cerr") + { + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << 2;)", "2"); + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << true;)", "true"); + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << false;)", "false"); + CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << "x=" << 2 << "\n";)", "x=2\n"); + } + + SECTION("runtime error") + { + std::string_view data_type = R"( +let f : R -> R, x -> 2; +cerr << "f=" << f << "\n"; +)"; + + std::string error_msg = "invalid argument, cannot print a 'function'"; + CHECK_OSTREAM_EXPRESSION_THROWS(data_type, error_msg); + } +} diff --git a/tests/test_PugsAssert.cpp b/tests/test_PugsAssert.cpp index b28ee88148cb0a3c39eb897a86918b17dad2199b..a7fa737f8d2ce1e8ed75a5865fd0f73799e613f6 100644 --- a/tests/test_PugsAssert.cpp +++ b/tests/test_PugsAssert.cpp @@ -11,11 +11,10 @@ TEST_CASE("PugsAssert", "[utils]") SECTION("checking for assert error") { const std::string filename = "filename"; - const int line = 10; + const size_t line = 10; const std::string function = "function"; - const std::string test = "test"; - AssertError assert_error(filename, line, function, test); + AssertError assert_error(filename, line, function, std::make_tuple("test"), "test"); REQUIRE(Catch::Detail::stringify(assert_error) == "\n---------- Assertion error -----------\n at filename:10\n in " "function\n assertion (test) " @@ -27,10 +26,8 @@ TEST_CASE("PugsAssert", "[utils]") const std::string filename = "filename"; const int line = 10; const std::string function = "function"; - const std::string test = "test"; - const std::string message = "message"; - AssertError assert_error(filename, line, function, test, message); + AssertError assert_error(filename, line, function, std::make_tuple(false, "message"), "test, message "); REQUIRE(Catch::Detail::stringify(assert_error) == "\n---------- Assertion error -----------\n at filename:10\n in " "function\n assertion (test) failed!\n " diff --git a/tests/test_PugsFunctionAdapter.cpp b/tests/test_PugsFunctionAdapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45229f8b599a1517fcd4c2182de563601643250d --- /dev/null +++ b/tests/test_PugsFunctionAdapter.cpp @@ -0,0 +1,389 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/utils/PugsFunctionAdapter.hpp> +#include <language/utils/SymbolTable.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionEvaluationExpressionBuilder.hpp> +#include <language/ast/ASTNodeFunctionExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +// clazy:excludeall=non-pod-global-static + +namespace tests_adapter +{ +template <typename T> +class TestBinary; +template <typename OutputType, typename... InputType> +class TestBinary<OutputType(InputType...)> : public PugsFunctionAdapter<OutputType(InputType...)> +{ + using Adapter = PugsFunctionAdapter<OutputType(InputType...)>; + + public: + template <typename ArgT> + static auto + one_arg(const FunctionSymbolId& function_symbol_id, const ArgT& x) + { + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + + auto& execution_policy = context_list[0]; + + Adapter::convertArgs(execution_policy.currentContext(), x); + auto result = expression.execute(execution_policy); + + return convert_result(std::move(result)); + } + + template <typename Arg1T, typename Arg2T> + static auto + two_args(const FunctionSymbolId& function_symbol_id, const Arg1T& x, const Arg2T& y) + { + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + + auto& execution_policy = context_list[0]; + + Adapter::convertArgs(execution_policy.currentContext(), x, y); + auto result = expression.execute(execution_policy); + + return convert_result(std::move(result)); + } +}; +} // namespace tests_adapter + +TEST_CASE("PugsFunctionAdapter", "[language]") +{ + SECTION("Valid calls") + { + std::string_view data = R"( +let Rtimes2: R -> R, x -> 2*x; +let BandB: B*B -> B, (a,b) -> a and b; +let NplusN: N*N -> N, (x,y) -> x+y; +let ZplusZ: Z*Z -> Z, (x,y) -> x+y; +let RplusR: R*R -> R, (x,y) -> x+y; +let RRtoR2: R*R -> R^2, (x,y) -> (x+y, x-y); +let R3times2: R^3 -> R^3, x -> 2*x; +let BtoR1: B -> R^1, b -> not b; +let NtoR1: N -> R^1, n -> n*n; +let ZtoR1: Z -> R^1, z -> -z; +let RtoR1: R -> R^1, x -> x*x; +let R3toR3zero: R^3 -> R^3, x -> 0; +)"; + string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this + + { + auto [i_symbol, found] = symbol_table->find("Rtimes2", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 2; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + double result = tests_adapter::TestBinary<double(double)>::one_arg(function_symbol_id, x); + + REQUIRE(result == (2 * x)); + } + + { + auto [i_symbol, found] = symbol_table->find("BandB", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const bool a = true; + const bool b = false; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + double result = tests_adapter::TestBinary<bool(bool, bool)>::two_args(function_symbol_id, a, b); + + REQUIRE(result == (a and b)); + } + + { + auto [i_symbol, found] = symbol_table->find("NplusN", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const uint64_t x = 2; + const uint64_t y = 3; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + double result = tests_adapter::TestBinary<uint64_t(uint64_t, uint64_t)>::two_args(function_symbol_id, x, y); + + REQUIRE(result == (x + y)); + } + + { + auto [i_symbol, found] = symbol_table->find("ZplusZ", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const int64_t x = 2; + const int64_t y = 3; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + double result = tests_adapter::TestBinary<int64_t(int64_t, int64_t)>::two_args(function_symbol_id, x, y); + + REQUIRE(result == (x + y)); + } + + { + auto [i_symbol, found] = symbol_table->find("RplusR", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 2; + const double y = 3; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + double result = tests_adapter::TestBinary<double(double, double)>::two_args(function_symbol_id, x, y); + + REQUIRE(result == (x + y)); + } + + { + auto [i_symbol, found] = symbol_table->find("RRtoR2", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 2; + const double y = 3; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<2> result = + tests_adapter::TestBinary<TinyVector<2>(double, double)>::two_args(function_symbol_id, x, y); + + REQUIRE(result == TinyVector<2>{x + y, x - y}); + } + + { + auto [i_symbol, found] = symbol_table->find("R3times2", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const TinyVector<3> x{2, 3, 4}; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<3> result = tests_adapter::TestBinary<TinyVector<3>(TinyVector<3>)>::one_arg(function_symbol_id, x); + + REQUIRE(result == 2 * x); + } + + { + auto [i_symbol, found] = symbol_table->find("BtoR1", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + { + const bool b = true; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<1> result = tests_adapter::TestBinary<TinyVector<1>(bool)>::one_arg(function_symbol_id, b); + + REQUIRE(result == not b); + } + + { + const bool b = false; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<1> result = tests_adapter::TestBinary<TinyVector<1>(bool)>::one_arg(function_symbol_id, b); + + REQUIRE(result == not b); + } + } + + { + auto [i_symbol, found] = symbol_table->find("NtoR1", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const uint64_t n = 4; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<1> result = tests_adapter::TestBinary<TinyVector<1>(uint64_t)>::one_arg(function_symbol_id, n); + + REQUIRE(result == n * n); + } + + { + auto [i_symbol, found] = symbol_table->find("ZtoR1", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const int64_t z = 3; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<1> result = tests_adapter::TestBinary<TinyVector<1>(int64_t)>::one_arg(function_symbol_id, z); + + REQUIRE(result == -z); + } + + { + auto [i_symbol, found] = symbol_table->find("RtoR1", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 3.3; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<1> result = tests_adapter::TestBinary<TinyVector<1>(double)>::one_arg(function_symbol_id, x); + + REQUIRE(result == x * x); + } + + { + auto [i_symbol, found] = symbol_table->find("R3toR3zero", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const TinyVector<3> x{1, 1, 1}; + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + TinyVector<3> result = tests_adapter::TestBinary<TinyVector<3>(TinyVector<3>)>::one_arg(function_symbol_id, x); + + REQUIRE(result == TinyVector<3>{0, 0, 0}); + } + } + + SECTION("Errors calls") + { + std::string_view data = R"( +let R1toR1: R^1 -> R^1, x -> x; +let R3toR3: R^3 -> R^3, x -> 1; +let RRRtoR3: R*R*R -> R^3, (x,y,z) -> (x,y,z); +let R3toR2: R^3 -> R^2, x -> (x[0],x[1]+x[2]); +let RtoNS: R -> N*string, x -> (1, "foo"); +let RtoR: R -> R, x -> 2*x; +)"; + string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + position position{internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this + + { + auto [i_symbol, found] = symbol_table->find("R1toR1", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const TinyVector<1> x{2}; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + REQUIRE_THROWS_WITH(tests_adapter::TestBinary<double(TinyVector<1>)>::one_arg(function_symbol_id, x), + "error: invalid function type\n" + "note: expecting R^1 -> R\n" + "note: provided function R1toR1: R^1 -> R^1"); + } + + { + auto [i_symbol, found] = symbol_table->find("R3toR3", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const TinyVector<3> x{2, 1, 3}; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + REQUIRE_THROWS_WITH(tests_adapter::TestBinary<TinyVector<3>(TinyVector<3>)>::one_arg(function_symbol_id, x), + "error: invalid function type\n" + "note: expecting R^3 -> R^3\n" + "note: provided function R3toR3: R^3 -> R^3"); + } + + { + auto [i_symbol, found] = symbol_table->find("RRRtoR3", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 1; + const double y = 2; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + REQUIRE_THROWS_WITH(tests_adapter::TestBinary<TinyVector<3>(double, double)>::two_args(function_symbol_id, x, y), + "error: invalid function type\n" + "note: expecting R*R -> R^3\n" + "note: provided function RRRtoR3: R*R*R -> R^3"); + } + + { + auto [i_symbol, found] = symbol_table->find("R3toR2", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 1; + const double y = 2; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + REQUIRE_THROWS_WITH(tests_adapter::TestBinary<TinyVector<3>(double, double)>::two_args(function_symbol_id, x, y), + "error: invalid function type\n" + "note: expecting R*R -> R^3\n" + "note: provided function R3toR2: R^3 -> R^2"); + } + + { + auto [i_symbol, found] = symbol_table->find("RtoNS", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 1; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + REQUIRE_THROWS_WITH(tests_adapter::TestBinary<TinyVector<2>(double)>::one_arg(function_symbol_id, x), + "error: invalid function type\n" + "note: expecting R -> R^2\n" + "note: provided function RtoNS: R -> N*string"); + } + + { + auto [i_symbol, found] = symbol_table->find("RtoR", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + const double x = 1; + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + REQUIRE_THROWS_WITH(tests_adapter::TestBinary<TinyVector<3>(double)>::one_arg(function_symbol_id, x), + "error: invalid function type\n" + "note: expecting R -> R^3\n" + "note: provided function RtoR: R -> R"); + } + } +} diff --git a/tests/test_SymbolTable.cpp b/tests/test_SymbolTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb80c4999781e59f3585f1ff64eba3ac3b71bcac --- /dev/null +++ b/tests/test_SymbolTable.cpp @@ -0,0 +1,222 @@ +#include <catch2/catch.hpp> + +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/SymbolTable.hpp> + +#include <pegtl/internal/iterator.hpp> + +#include <sstream> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SymbolTable", "[language]") +{ + SECTION("Simple Symbol Table") + { + std::shared_ptr root_st = std::make_shared<SymbolTable>(); + + using namespace TAO_PEGTL_NAMESPACE; + position begin_position{internal::iterator{"fixture"}, "fixture"}; + begin_position.byte = 2; + + auto [i_symbol_a, created_a] = root_st->add("a", begin_position); + REQUIRE(created_a); + + REQUIRE(i_symbol_a->attributes().position().byte == 2); + + // Check that one cannot build another "a" in this table + REQUIRE(not root_st->add("a", begin_position).second); + + position use_position{internal::iterator{"fixture"}, "fixture"}; + use_position.byte = 3; // after declarative position + + auto [i_search_a, found_a] = root_st->find("a", use_position); + REQUIRE(found_a); + REQUIRE(i_search_a == i_symbol_a); + + SECTION("Output uninitialized") + { + std::stringstream st_output; + st_output << '\n' << *root_st; + + std::stringstream expected_output; + expected_output << '\n' + << "-- Symbol table state -- parent : " << static_cast<SymbolTable*>(nullptr) << '\n' + << " a: undefined:--\n" + << "------------------------\n"; + + REQUIRE(st_output.str() == expected_output.str()); + } + + SECTION("Attributes") + { + // undefined data + auto& attributes_a = i_search_a->attributes(); + REQUIRE(attributes_a.dataType() == ASTNodeDataType::undefined_t); + REQUIRE(not attributes_a.isInitialized()); + + REQUIRE(std::holds_alternative<std::monostate>(attributes_a.value())); + + { + std::stringstream value_output; + value_output << attributes_a; + REQUIRE(value_output.str() == "undefined:--"); + } + + // defining data + attributes_a.setIsInitialized(); + REQUIRE(attributes_a.isInitialized()); + + attributes_a.setDataType(ASTNodeDataType::double_t); + REQUIRE(attributes_a.dataType() == ASTNodeDataType::double_t); + + attributes_a.value() = 2.3; + + REQUIRE(std::holds_alternative<double>(attributes_a.value())); + + const auto const_attribute_a = attributes_a; + REQUIRE(std::get<double>(const_attribute_a.value()) == 2.3); + + { + std::stringstream value_output; + value_output << attributes_a; + REQUIRE(value_output.str() == "R:2.3"); + } + + SECTION("Output initialized") + { + std::stringstream st_output; + st_output << '\n' << *root_st; + + std::stringstream expected_output; + expected_output << '\n' + << "-- Symbol table state -- parent : " << static_cast<SymbolTable*>(nullptr) << '\n' + << " a: R:2.3\n" + << "------------------------\n"; + + REQUIRE(st_output.str() == expected_output.str()); + } + } + } + + SECTION("Hierarchy Symbol Table") + { + std::shared_ptr root_st = std::make_shared<SymbolTable>(); + + using namespace TAO_PEGTL_NAMESPACE; + position begin_position{internal::iterator{"fixture"}, "fixture"}; + position end_declaration{internal::iterator{"fixture"}, "fixture"}; + + auto [i_root_symbol_a, created_root_a] = root_st->add("a", begin_position); + REQUIRE(created_root_a); + + std::shared_ptr nested_st = std::make_shared<SymbolTable>(root_st); + + position use_position{internal::iterator{"fixture"}, "fixture"}; + auto [i_search_a, found_a] = nested_st->find("a", use_position); + REQUIRE(found_a); + // symbol "a" is the one defined in root_st + REQUIRE(i_root_symbol_a == i_search_a); + + auto [i_nested_symbol_a, created_nested_a] = nested_st->add("a", begin_position); + REQUIRE(created_nested_a); + + auto [i_search_nested_a, found_nested_a] = nested_st->find("a", use_position); + + REQUIRE(found_nested_a); + // found the symbol created in nested symbol table + REQUIRE(&(i_search_nested_a->attributes()) != &(i_root_symbol_a->attributes())); + REQUIRE(&(i_search_nested_a->attributes()) == &(i_nested_symbol_a->attributes())); + + auto [i_search_b, found_b] = nested_st->find("b", use_position); + REQUIRE(not found_b); // "b" is not defined in any symbol table + } + + SECTION("Output of function_id") + { + std::shared_ptr root_st = std::make_shared<SymbolTable>(); + + using namespace TAO_PEGTL_NAMESPACE; + position begin_position{internal::iterator{"fixture"}, "fixture"}; + begin_position.byte = 2; + + auto [i_symbol_a, created_a] = root_st->add("a", begin_position); + REQUIRE(i_symbol_a->attributes().position().byte == 2); + + position use_position{internal::iterator{"fixture"}, "fixture"}; + use_position.byte = 3; // after declarative position + + auto [i_search_a, found_a] = root_st->find("a", use_position); + REQUIRE(found_a); + REQUIRE(i_search_a == i_symbol_a); + + auto& attributes_a = i_search_a->attributes(); + REQUIRE(attributes_a.dataType() == ASTNodeDataType::undefined_t); + REQUIRE(not attributes_a.isInitialized()); + + REQUIRE(std::holds_alternative<std::monostate>(attributes_a.value())); + + { + std::stringstream value_output; + value_output << attributes_a; + REQUIRE(value_output.str() == "undefined:--"); + } + + // defining function data + attributes_a.setIsInitialized(); + REQUIRE(attributes_a.isInitialized()); + + attributes_a.setDataType(ASTNodeDataType::function_t); + REQUIRE(attributes_a.dataType() == ASTNodeDataType::function_t); + + attributes_a.value() = static_cast<uint64_t>(2); + + REQUIRE(std::holds_alternative<uint64_t>(attributes_a.value())); + + { + std::stringstream value_output; + value_output << attributes_a; + REQUIRE(value_output.str() == "function_id:2"); + } + + { + const SymbolTable::Symbol symbol{i_symbol_a->name(), i_symbol_a->attributes()}; + std::stringstream value_output; + value_output << symbol.attributes(); + REQUIRE(value_output.str() == "function_id:2"); + } + } + + SECTION("FunctionTable") + { + std::shared_ptr root_st = std::make_shared<SymbolTable>(); + + auto& function_table = root_st->functionTable(); + REQUIRE(function_table.size() == 0); + + const auto& const_function_table = static_cast<const SymbolTable&>(*root_st).functionTable(); + REQUIRE(const_function_table.size() == 0); + + function_table.add(FunctionDescriptor{}); + + REQUIRE(function_table.size() == 1); + REQUIRE(const_function_table.size() == 1); + } + + SECTION("BuiltinFunctionEmbedderTable") + { + std::shared_ptr root_st = std::make_shared<SymbolTable>(); + + auto& builtin_function_table = root_st->builtinFunctionEmbedderTable(); + REQUIRE(builtin_function_table.size() == 0); + + const auto& const_builtin_function_table = static_cast<const SymbolTable&>(*root_st).builtinFunctionEmbedderTable(); + REQUIRE(const_builtin_function_table.size() == 0); + + builtin_function_table.add( + std::make_shared<BuiltinFunctionEmbedder<double(double)>>([](double) -> double { return 0; })); + + REQUIRE(builtin_function_table.size() == 1); + REQUIRE(const_builtin_function_table.size() == 1); + } +} diff --git a/tests/test_TupleToVectorProcessor.cpp b/tests/test_TupleToVectorProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ddbf513d35470dbd39d6a5842fdfc37b75e5eaf --- /dev/null +++ b/tests/test_TupleToVectorProcessor.cpp @@ -0,0 +1,94 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTModulesImporter.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_EVALUATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_EVALUATION_THROWS_WITH(data, error_message) \ + { \ + auto eval = [&] { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + }; \ + \ + REQUIRE_THROWS_WITH(eval(), error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TupleToVectorProcessor", "[language]") +{ + SECTION("Return tuple -> R^3") + { + std::string_view data = R"( +let f: R*R*R->R^3, (x,y,z) -> (x,y,z); +let x:R^3, x = f(1,2,3); +)"; + CHECK_EVALUATION_RESULT(data, "x", (TinyVector<3>{1, 2, 3})); + } + + SECTION("Return tuple -> R^2") + { + std::string_view data = R"( +let f: R^3->R^2, x -> (x[2],x[1]); +let x:R^3, x = (1,2,3); +let y:R^2, y = f(x); +)"; + CHECK_EVALUATION_RESULT(data, "y", (TinyVector<2>{3, 2})); + } +} diff --git a/tests/test_UnaryExpressionProcessor.cpp b/tests/test_UnaryExpressionProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e933902adaefd968cc3036c8bbf007b29d054f39 --- /dev/null +++ b/tests/test_UnaryExpressionProcessor.cpp @@ -0,0 +1,80 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_UNARY_EXPRESSION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_UNARY_EXPRESSION_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("UnaryExpressionProcessor", "[language]") +{ + SECTION("unary minus") + { + CHECK_UNARY_EXPRESSION_RESULT(R"(let n:N, n = 2; let z:Z, z = -n;)", "z", -2l); + CHECK_UNARY_EXPRESSION_RESULT(R"(let p:Z, p = 2; let q:Z, q = -p;)", "q", -2l); + CHECK_UNARY_EXPRESSION_RESULT(R"(let r:R, r = 2; r = -r;)", "r", -2.); + } + + SECTION("unary not") + { + CHECK_UNARY_EXPRESSION_RESULT(R"(let b:B, b = false; b = not b;)", "b", true); + CHECK_UNARY_EXPRESSION_RESULT(R"(let b:B, b = true; b = not b;)", "b", false); + + SECTION("errors") + { + SECTION("bad implicit conversions") + { + CHECK_UNARY_EXPRESSION_THROWS_WITH(R"(let n:N, n = 0; not n;)", "invalid implicit conversion: N -> B"); + CHECK_UNARY_EXPRESSION_THROWS_WITH(R"(not 1;)", "invalid implicit conversion: Z -> B"); + CHECK_UNARY_EXPRESSION_THROWS_WITH(R"(not 1.3;)", "invalid implicit conversion: R -> B"); + CHECK_UNARY_EXPRESSION_THROWS_WITH(R"(not "foo";)", "invalid implicit conversion: string -> B"); + } + } + } +} diff --git a/tests/test_WhileProcessor.cpp b/tests/test_WhileProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a823c068f92013530b4622ef665f9ed3a4713db --- /dev/null +++ b/tests/test_WhileProcessor.cpp @@ -0,0 +1,111 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_WHILE_PROCESSOR_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_WHILE_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("WhileProcessor", "[language]") +{ + SECTION("simple loop") + { + std::string_view data = R"( +let i:N, i = 3; +let j:N, j = 0; +while(i<10) { + j++; + i += j; +} +)"; + CHECK_WHILE_PROCESSOR_RESULT(data, "i", 13ul); + } + + SECTION("simple with break") + { + std::string_view data = R"( +let i:N, i = 3; +let j:N, j = 0; +while(i<10) { + j++; + if (j==2) break; + i += j; +} +)"; + CHECK_WHILE_PROCESSOR_RESULT(data, "i", 4ul); + } + + SECTION("simple with continue") + { + std::string_view data = R"( +let i:N, i = 3; +let j:N, j = 0; +while(i<10) { + j++; + if (j<=3) continue; + i += j; +} +)"; + CHECK_WHILE_PROCESSOR_RESULT(data, "i", 12ul); + } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +while(1) { +} +)"; + + CHECK_WHILE_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: Z -> B"); + } + } +}