├── .clang-format ├── .clang-tidy ├── .github ├── funding.yml └── workflows │ ├── codeql.yml │ ├── feature_ci.yml │ ├── main_ci.yml │ ├── release.yml │ ├── sanitizers.yml │ └── website.yml ├── .gitignore ├── CHANGELOG.adoc ├── CMakeLists.txt ├── LICENSE ├── README.adoc ├── benchmarks ├── CMakeLists.txt ├── file │ ├── CMakeLists.txt │ └── main.cpp ├── json │ ├── CMakeLists.txt │ ├── baseline.cpp │ ├── boost.cpp │ ├── lexy.cpp │ ├── main.cpp │ ├── nlohmann.cpp │ ├── pegtl.cpp │ └── rapidjson.cpp └── swar │ ├── CMakeLists.txt │ ├── any.cpp │ ├── delimited.cpp │ ├── digits.cpp │ ├── identifier.cpp │ ├── literal.cpp │ ├── main.cpp │ ├── swar.hpp │ └── until.cpp ├── cmake └── lexyConfig.cmake.in ├── docs ├── CMakeLists.txt ├── archetypes │ ├── default.md │ └── dsl.adoc ├── assets │ ├── cpp │ │ ├── godbolt_main.cpp │ │ ├── godbolt_prefix.cpp │ │ ├── playground_headers.hpp │ │ ├── playground_main.cpp │ │ └── playground_prefix.cpp │ ├── css │ │ ├── _base.scss │ │ ├── playground.scss │ │ └── style.scss │ ├── examples │ │ ├── argv_input.cpp │ │ ├── argv_input.input │ │ ├── argv_iterator.cpp │ │ ├── argv_iterator.input │ │ ├── as_list-allocator.cpp │ │ ├── as_list.cpp │ │ ├── as_list.input │ │ ├── bind-constant.cpp │ │ ├── bind-fallback.cpp │ │ ├── bind-fallback.input │ │ ├── bind-parse_state.cpp │ │ ├── bind-parse_state.input │ │ ├── bind-reorder-map.cpp │ │ ├── bind-values.cpp │ │ ├── bind_sink-parse_state.cpp │ │ ├── bits.cpp │ │ ├── bom.cpp │ │ ├── buffer.cpp │ │ ├── callback-fold.cpp │ │ ├── callback.cpp │ │ ├── capture.cpp │ │ ├── capture.input │ │ ├── code_point_id.cpp │ │ ├── code_point_id.input │ │ ├── code_unit_id.cpp │ │ ├── code_unit_id.input │ │ ├── color.cpp │ │ ├── color.input │ │ ├── compose-callback.cpp │ │ ├── compose-sink.cpp │ │ ├── compose-sink.input │ │ ├── concat.cpp │ │ ├── concat.input │ │ ├── flags.cpp │ │ ├── flags.input │ │ ├── fold.cpp │ │ ├── fold.input │ │ ├── fold_inplace.cpp │ │ ├── fold_inplace.input │ │ ├── identifier_case_folded.cpp │ │ ├── identifier_case_folded.input │ │ ├── integer.cpp │ │ ├── integer.input │ │ ├── list.cpp │ │ ├── list.input │ │ ├── list_sep.cpp │ │ ├── list_sep.input │ │ ├── lookahead.cpp │ │ ├── lookahead.input │ │ ├── make_buffer.cpp │ │ ├── member.cpp │ │ ├── member.input │ │ ├── new.cpp │ │ ├── new.input │ │ ├── noop.cpp │ │ ├── op-basic.cpp │ │ ├── op-basic.input │ │ ├── op-choice.cpp │ │ ├── op-choice.input │ │ ├── op-custom.cpp │ │ ├── op-custom.input │ │ ├── opt.cpp │ │ ├── opt.input │ │ ├── parse_tree_parsing.cpp │ │ ├── parse_tree_parsing.input │ │ ├── point.cpp │ │ ├── point.input │ │ ├── quoted_escape.cpp │ │ ├── quoted_escape.input │ │ ├── range_input.cpp │ │ ├── scan.cpp │ │ ├── scan.input │ │ ├── sign.cpp │ │ ├── sign.input │ │ ├── string_input.cpp │ │ ├── symbol.cpp │ │ ├── symbol.input │ │ ├── times_isep.cpp │ │ ├── times_isep.input │ │ ├── times_tsep.cpp │ │ ├── times_tsep.input │ │ ├── token_kind_map.cpp │ │ ├── token_kind_map.input │ │ ├── true_false.cpp │ │ ├── true_false.input │ │ ├── try.cpp │ │ ├── try.input │ │ ├── visualize.cpp │ │ ├── visualize.input │ │ └── zstring_input.cpp │ ├── icons │ │ ├── arrow-left.svg │ │ ├── arrow-right.svg │ │ ├── arrow-up.svg │ │ ├── beta.svg │ │ ├── bug.svg │ │ ├── calender.svg │ │ ├── download.svg │ │ ├── edit.svg │ │ ├── github.svg │ │ ├── license.svg │ │ └── play.svg │ ├── js │ │ └── playground.js │ ├── jsconfig.json │ └── playground │ │ ├── any.cpp │ │ ├── case_folding.cpp │ │ ├── char_class_intersection.cpp │ │ ├── char_class_macro.cpp │ │ ├── char_class_minus.cpp │ │ ├── char_class_union.cpp │ │ ├── choice.cpp │ │ ├── choice_bad.cpp │ │ ├── choice_branch.cpp │ │ ├── choice_else.cpp │ │ ├── choice_error.cpp │ │ ├── choice_error_range.cpp │ │ ├── choice_production.cpp │ │ ├── code_point.cpp │ │ ├── code_point_if.cpp │ │ ├── color.cpp │ │ ├── color_function.cpp │ │ ├── combination.cpp │ │ ├── context_counter.cpp │ │ ├── context_flag.cpp │ │ ├── context_identifier.cpp │ │ ├── cpp_comment.cpp │ │ ├── default.cpp │ │ ├── digit.cpp │ │ ├── digits.cpp │ │ ├── do_while.cpp │ │ ├── eof.cpp │ │ ├── eol.cpp │ │ ├── equal_counts.cpp │ │ ├── exhausted_choice.cpp │ │ ├── expected_char_class.cpp │ │ ├── expected_literal.cpp │ │ ├── expr.cpp │ │ ├── expr_groups.cpp │ │ ├── find.cpp │ │ ├── identifier-unicode.cpp │ │ ├── identifier.cpp │ │ ├── if.cpp │ │ ├── infix_op_left.cpp │ │ ├── infix_op_list.cpp │ │ ├── infix_op_right.cpp │ │ ├── infix_op_single.cpp │ │ ├── inline.cpp │ │ ├── keyword.cpp │ │ ├── lit.cpp │ │ ├── lit_ascii.cpp │ │ ├── lit_cp.cpp │ │ ├── lit_utf8.cpp │ │ ├── literal_set.cpp │ │ ├── loop.cpp │ │ ├── manual_whitespace.cpp │ │ ├── minus_sign.cpp │ │ ├── must.cpp │ │ ├── n_digits.cpp │ │ ├── newline.cpp │ │ ├── no_trailing.cpp │ │ ├── no_whitespace.cpp │ │ ├── not_followed_by.cpp │ │ ├── one_of.cpp │ │ ├── parenthesized.cpp │ │ ├── partial_combination.cpp │ │ ├── peek.cpp │ │ ├── peek_not.cpp │ │ ├── plus_sign.cpp │ │ ├── position.cpp │ │ ├── postfix_op.cpp │ │ ├── prefix_op.cpp │ │ ├── quoted.cpp │ │ ├── quoted_error.cpp │ │ ├── quoted_limit.cpp │ │ ├── quoted_token.cpp │ │ ├── recover.cpp │ │ ├── recurse.cpp │ │ ├── recurse_limit.cpp │ │ ├── repeat.cpp │ │ ├── reserved_identifier.cpp │ │ ├── reserved_identifier_case_folding.cpp │ │ ├── return.cpp │ │ ├── scan-recovery.cpp │ │ ├── scan.cpp │ │ ├── terminator.cpp │ │ ├── terminator_list.cpp │ │ ├── terminator_opt.cpp │ │ ├── terminator_recovery.cpp │ │ ├── terminator_try.cpp │ │ ├── trace.cpp │ │ ├── while.cpp │ │ ├── while_bad.cpp │ │ ├── while_one.cpp │ │ ├── whitespace.cpp │ │ ├── whitespace_comment.cpp │ │ ├── whitespace_determination.cpp │ │ └── zero.cpp ├── config.toml ├── content │ ├── benchmark_json.adoc │ ├── download │ │ └── _index.adoc │ ├── learn │ │ ├── _index.adoc │ │ ├── branching.adoc │ │ ├── build.adoc │ │ ├── versioning.adoc │ │ ├── walkthrough.adoc │ │ └── warmup.adoc │ ├── playground │ │ └── _index.md │ └── reference │ │ ├── _index.adoc │ │ ├── action │ │ ├── match.adoc │ │ ├── parse.adoc │ │ ├── parse_as_tree.adoc │ │ ├── scan.adoc │ │ ├── trace.adoc │ │ └── validate.adoc │ │ ├── callback │ │ ├── _index.adoc │ │ ├── adapter.adoc │ │ ├── aggregate.adoc │ │ ├── bind.adoc │ │ ├── bit_cast.adoc │ │ ├── composition.adoc │ │ ├── constant.adoc │ │ ├── container.adoc │ │ ├── fold.adoc │ │ ├── forward.adoc │ │ ├── integer.adoc │ │ ├── noop.adoc │ │ ├── object.adoc │ │ └── string.adoc │ │ ├── code_point.adoc │ │ ├── dsl │ │ ├── _index.adoc │ │ ├── any.adoc │ │ ├── ascii.adoc │ │ ├── bits.adoc │ │ ├── bom.adoc │ │ ├── brackets.adoc │ │ ├── branch.adoc │ │ ├── byte.adoc │ │ ├── capture.adoc │ │ ├── case_folding.adoc │ │ ├── char_class.adoc │ │ ├── choice.adoc │ │ ├── code_point.adoc │ │ ├── combination.adoc │ │ ├── context_counter.adoc │ │ ├── context_flag.adoc │ │ ├── context_identifier.adoc │ │ ├── delimited.adoc │ │ ├── digit.adoc │ │ ├── effect.adoc │ │ ├── eof.adoc │ │ ├── error.adoc │ │ ├── expression.adoc │ │ ├── flags.adoc │ │ ├── follow.adoc │ │ ├── identifier.adoc │ │ ├── if.adoc │ │ ├── integer.adoc │ │ ├── list.adoc │ │ ├── literal.adoc │ │ ├── lookahead.adoc │ │ ├── loop.adoc │ │ ├── member.adoc │ │ ├── newline.adoc │ │ ├── operator.adoc │ │ ├── option.adoc │ │ ├── parse_as.adoc │ │ ├── parse_tree_node.adoc │ │ ├── peek.adoc │ │ ├── position.adoc │ │ ├── production.adoc │ │ ├── punctuator.adoc │ │ ├── recover.adoc │ │ ├── repeat.adoc │ │ ├── return.adoc │ │ ├── scan.adoc │ │ ├── separator.adoc │ │ ├── sequence.adoc │ │ ├── sign.adoc │ │ ├── subgrammar.adoc │ │ ├── symbol.adoc │ │ ├── terminator.adoc │ │ ├── times.adoc │ │ ├── token.adoc │ │ ├── unicode.adoc │ │ ├── until.adoc │ │ └── whitespace.adoc │ │ ├── encoding.adoc │ │ ├── error.adoc │ │ ├── grammar.adoc │ │ ├── input │ │ ├── argv_input.adoc │ │ ├── buffer.adoc │ │ ├── file.adoc │ │ ├── lexeme_input.adoc │ │ ├── parse_tree_input.adoc │ │ ├── range_input.adoc │ │ └── string_input.adoc │ │ ├── input_location.adoc │ │ ├── lexeme.adoc │ │ ├── parse_tree.adoc │ │ ├── token.adoc │ │ └── visualize.adoc ├── data │ └── tags │ │ ├── v2022.05.0-beta.toml │ │ ├── v2022.05.1.toml │ │ ├── v2022.12.0.toml │ │ ├── v2022.12.1.toml │ │ └── v2025.05.0.toml ├── layouts │ ├── _default │ │ ├── baseof.html │ │ ├── list.html │ │ └── single.html │ ├── partials │ │ └── toc.html │ ├── playground │ │ └── playground.html │ ├── reference │ │ ├── list.json.json │ │ └── single.html │ └── shortcodes │ │ ├── branch-rule.adoc │ │ ├── char-class-rule.adoc │ │ ├── docref.adoc │ │ ├── encoding.adoc │ │ ├── error-callback.adoc │ │ ├── experimental.html │ │ ├── github-example.html │ │ ├── godbolt-example.adoc │ │ ├── headerref.adoc │ │ ├── interface.adoc │ │ ├── literal-rule.adoc │ │ ├── playground-example.adoc │ │ ├── release_list.adoc │ │ ├── release_selection.adoc │ │ ├── rule.adoc │ │ ├── svg.html │ │ └── token-rule.adoc └── static │ ├── .nojekyll │ └── CNAME ├── examples ├── CMakeLists.txt ├── calculator.cpp ├── config.cpp ├── email.cpp ├── ip_address.cpp ├── json.cpp ├── protobuf.cpp ├── shell.cpp ├── turing.cpp └── xml.cpp ├── include ├── lexy │ ├── _detail │ │ ├── any_ref.hpp │ │ ├── assert.hpp │ │ ├── buffer_builder.hpp │ │ ├── code_point.hpp │ │ ├── config.hpp │ │ ├── detect.hpp │ │ ├── integer_sequence.hpp │ │ ├── invoke.hpp │ │ ├── iterator.hpp │ │ ├── lazy_init.hpp │ │ ├── memory_resource.hpp │ │ ├── nttp_string.hpp │ │ ├── stateless_lambda.hpp │ │ ├── std.hpp │ │ ├── string_view.hpp │ │ ├── swar.hpp │ │ ├── tuple.hpp │ │ ├── type_name.hpp │ │ └── unicode_database.hpp │ ├── action │ │ ├── base.hpp │ │ ├── match.hpp │ │ ├── parse.hpp │ │ ├── parse_as_tree.hpp │ │ ├── scan.hpp │ │ ├── trace.hpp │ │ └── validate.hpp │ ├── callback.hpp │ ├── callback │ │ ├── adapter.hpp │ │ ├── aggregate.hpp │ │ ├── base.hpp │ │ ├── bind.hpp │ │ ├── bit_cast.hpp │ │ ├── composition.hpp │ │ ├── constant.hpp │ │ ├── container.hpp │ │ ├── fold.hpp │ │ ├── forward.hpp │ │ ├── integer.hpp │ │ ├── noop.hpp │ │ ├── object.hpp │ │ └── string.hpp │ ├── code_point.hpp │ ├── dsl.hpp │ ├── dsl │ │ ├── any.hpp │ │ ├── ascii.hpp │ │ ├── base.hpp │ │ ├── bits.hpp │ │ ├── bom.hpp │ │ ├── brackets.hpp │ │ ├── branch.hpp │ │ ├── byte.hpp │ │ ├── capture.hpp │ │ ├── case_folding.hpp │ │ ├── char_class.hpp │ │ ├── choice.hpp │ │ ├── code_point.hpp │ │ ├── combination.hpp │ │ ├── context_counter.hpp │ │ ├── context_flag.hpp │ │ ├── context_identifier.hpp │ │ ├── delimited.hpp │ │ ├── digit.hpp │ │ ├── effect.hpp │ │ ├── eof.hpp │ │ ├── error.hpp │ │ ├── expression.hpp │ │ ├── flags.hpp │ │ ├── follow.hpp │ │ ├── identifier.hpp │ │ ├── if.hpp │ │ ├── integer.hpp │ │ ├── list.hpp │ │ ├── literal.hpp │ │ ├── lookahead.hpp │ │ ├── loop.hpp │ │ ├── member.hpp │ │ ├── newline.hpp │ │ ├── operator.hpp │ │ ├── option.hpp │ │ ├── parse_as.hpp │ │ ├── parse_tree_node.hpp │ │ ├── peek.hpp │ │ ├── position.hpp │ │ ├── production.hpp │ │ ├── punctuator.hpp │ │ ├── recover.hpp │ │ ├── repeat.hpp │ │ ├── return.hpp │ │ ├── scan.hpp │ │ ├── separator.hpp │ │ ├── sequence.hpp │ │ ├── sign.hpp │ │ ├── subgrammar.hpp │ │ ├── symbol.hpp │ │ ├── terminator.hpp │ │ ├── times.hpp │ │ ├── token.hpp │ │ ├── unicode.hpp │ │ ├── until.hpp │ │ └── whitespace.hpp │ ├── encoding.hpp │ ├── error.hpp │ ├── grammar.hpp │ ├── input │ │ ├── argv_input.hpp │ │ ├── base.hpp │ │ ├── buffer.hpp │ │ ├── file.hpp │ │ ├── lexeme_input.hpp │ │ ├── parse_tree_input.hpp │ │ ├── range_input.hpp │ │ └── string_input.hpp │ ├── input_location.hpp │ ├── lexeme.hpp │ ├── parse_tree.hpp │ ├── token.hpp │ └── visualize.hpp └── lexy_ext │ ├── compiler_explorer.hpp │ ├── parse_tree_algorithm.hpp │ ├── parse_tree_doctest.hpp │ ├── report_error.hpp │ └── shell.hpp ├── src ├── CMakeLists.txt └── input │ └── file.cpp ├── support ├── generate-unicode-db.py └── resolve-lexy-headers.py └── tests ├── CMakeLists.txt ├── doctest_main.cpp ├── examples ├── CMakeLists.txt ├── calculator.cpp ├── email.cpp ├── ip_address.cpp ├── json.cpp ├── protobuf.cpp ├── shell.cpp ├── turing.cpp └── xml.cpp ├── lexy ├── CMakeLists.txt ├── action │ ├── base.cpp │ ├── match.cpp │ ├── parse.cpp │ ├── parse_as_tree.cpp │ ├── scan.cpp │ ├── trace.cpp │ └── validate.cpp ├── callback.cpp ├── callback │ ├── adapter.cpp │ ├── aggregate.cpp │ ├── base.cpp │ ├── bind.cpp │ ├── bit_cast.cpp │ ├── composition.cpp │ ├── constant.cpp │ ├── container.cpp │ ├── fold.cpp │ ├── forward.cpp │ ├── integer.cpp │ ├── noop.cpp │ ├── object.cpp │ └── string.cpp ├── code_point.cpp ├── detail │ ├── any_ref.cpp │ ├── buffer_builder.cpp │ ├── integer_sequence.cpp │ ├── invoke.cpp │ ├── lazy_init.cpp │ ├── nttp_string.cpp │ ├── stateless_lambda.cpp │ ├── std.cpp │ ├── string_view.cpp │ ├── swar.cpp │ ├── tuple.cpp │ └── type_name.cpp ├── dsl │ ├── any.cpp │ ├── argv_input.cpp │ ├── ascii.cpp │ ├── base.cpp │ ├── bits.cpp │ ├── bom.cpp │ ├── brackets.cpp │ ├── branch.cpp │ ├── byte.cpp │ ├── capture.cpp │ ├── case_folding.cpp │ ├── char_class.cpp │ ├── choice.cpp │ ├── code_point.cpp │ ├── combination.cpp │ ├── context_counter.cpp │ ├── context_flag.cpp │ ├── context_identifier.cpp │ ├── delimited.cpp │ ├── digit.cpp │ ├── effect.cpp │ ├── eof.cpp │ ├── error.cpp │ ├── expression.cpp │ ├── flags.cpp │ ├── follow.cpp │ ├── identifier.cpp │ ├── if.cpp │ ├── integer.cpp │ ├── list.cpp │ ├── literal.cpp │ ├── lookahead.cpp │ ├── loop.cpp │ ├── member.cpp │ ├── newline.cpp │ ├── operator.cpp │ ├── option.cpp │ ├── parse_as.cpp │ ├── parse_tree_node.cpp │ ├── peek.cpp │ ├── position.cpp │ ├── production.cpp │ ├── punctuator.cpp │ ├── recover.cpp │ ├── repeat.cpp │ ├── return.cpp │ ├── scan.cpp │ ├── separator.cpp │ ├── sequence.cpp │ ├── sign.cpp │ ├── subgrammar.cpp │ ├── subgrammar_other.cpp │ ├── symbol.cpp │ ├── terminator.cpp │ ├── times.cpp │ ├── token.cpp │ ├── trace.cpp │ ├── unicode.cpp │ ├── until.cpp │ ├── verify.hpp │ └── whitespace.cpp ├── encoding.cpp ├── error.cpp ├── grammar.cpp ├── input │ ├── argv_input.cpp │ ├── base.cpp │ ├── buffer.cpp │ ├── file.cpp │ ├── lexeme_input.cpp │ ├── parse_tree_input.cpp │ ├── range_input.cpp │ └── string_input.cpp ├── input_location.cpp ├── lexeme.cpp ├── parse_tree.cpp ├── test_encoding.hpp ├── token.cpp └── visualize.cpp ├── lexy_ext ├── CMakeLists.txt ├── compiler_explorer.cpp ├── parse_tree_algorithm.cpp ├── parse_tree_doctest.cpp ├── report_error.cpp └── shell.cpp └── playground ├── CMakeLists.txt ├── godbolt.cpp └── playground.cpp /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: > 2 | -*, 3 | bugprone-*, 4 | -bugprone-exception-escape, 5 | -bugprone-easily-swappable-parameters, 6 | -clang-analyzer-*, 7 | misc-*, 8 | -misc-const-correctness, 9 | -misc-definitions-in-headers, 10 | -misc-include-cleaner, 11 | -misc-no-recursion, 12 | -misc-non-private-member-variables-in-classes, 13 | -misc-static-assert, 14 | -misc-unused-alias-decls, 15 | -misc-use-anonymous-namespace, 16 | performance-*, 17 | -performance-enum-size, 18 | readability-*, 19 | -readability-braces-around-statements, 20 | -readability-convert-member-functions-to-static, 21 | -readability-else-after-return, 22 | -readability-function-cognitive-complexity, 23 | -readability-function-size, 24 | -readability-identifier-length, 25 | -readability-magic-numbers, 26 | -readability-make-member-function-const, 27 | -readability-misleading-indentation, 28 | -readability-named-parameter, 29 | -readability-qualified-auto, 30 | -readability-redundant-access-specifiers, 31 | -readability-redundant-declaration, 32 | -readability-static-accessed-through-instance, 33 | -readability-suspicious-call-argument, 34 | -readability-uppercase-literal-suffix, 35 | WarningsAsErrors: '*' 36 | FormatStyle: 'file' 37 | HeaderFilterRegex: 'include/lexy(_ext)?/' 38 | 39 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | patreon: foonathan 2 | custom: ['https://jonathanmueller.dev/support-me/'] 3 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL 2 | 3 | on: 4 | push: 5 | branches: [main, fix/*] 6 | schedule: 7 | - cron: '30 1 * * 2' 8 | 9 | jobs: 10 | codeql: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Install ninja 16 | run: sudo apt-get -qq update && sudo apt-get install -y ninja-build 17 | - name: Initialize CodeQL 18 | uses: github/codeql-action/init@v3 19 | with: 20 | languages: cpp 21 | 22 | - name: Create Build Environment 23 | run: cmake -E make_directory build 24 | - name: Configure 25 | working-directory: build/ 26 | run: cmake -GNinja $GITHUB_WORKSPACE 27 | - name: Build 28 | working-directory: build/ 29 | run: cmake --build . 30 | - name: Perform CodeQL analysis 31 | uses: github/codeql-action/analyze@v3 32 | 33 | -------------------------------------------------------------------------------- /.github/workflows/website.yml: -------------------------------------------------------------------------------- 1 | name: Website 2 | permissions: 3 | contents: write 4 | 5 | on: 6 | push: 7 | branches: '**' 8 | pull_request: 9 | 10 | jobs: 11 | website: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Install asciidoctor 17 | run: sudo gem install asciidoctor pygments.rb 18 | - name: Install hugo 19 | uses: peaceiris/actions-hugo@v2 20 | with: 21 | hugo-version: 'latest' 22 | extended: true 23 | 24 | - name: Create Build Environment 25 | run: cmake -E make_directory build 26 | - name: Configure 27 | working-directory: build/ 28 | run: cmake $GITHUB_WORKSPACE -DLEXY_BUILD_DOCS=ON -DLEXY_BUILD_EXAMPLES=OFF -DLEXY_BUILD_TESTS=OFF 29 | - name: Build docs 30 | working-directory: build/ 31 | run: cmake --build . --target lexy_docs 32 | 33 | - name: Deploy 34 | if: github.ref == 'refs/heads/main' 35 | uses: peaceiris/actions-gh-pages@v3 36 | with: 37 | github_token: ${{ secrets.GITHUB_TOKEN }} 38 | publish_dir: ./docs/public/ 39 | 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs/assets/cpp/playground_headers.single.hpp 2 | docs/content/_index.adoc 3 | docs/content/learn/changelog.adoc 4 | docs/data/tags/head.toml 5 | docs/static/download/*.zip 6 | docs/public/ 7 | docs/resources/ 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | # SPDX-License-Identifier: BSL-1.0 3 | 4 | # Fetch nanobench. 5 | message(STATUS "Fetching nanobench") 6 | include(FetchContent) 7 | FetchContent_Declare(nanobench URL https://github.com/martinus/nanobench/archive/v4.3.0.zip) 8 | FetchContent_MakeAvailable(nanobench) 9 | 10 | add_subdirectory(json) 11 | add_subdirectory(file) 12 | add_subdirectory(swar) 13 | 14 | -------------------------------------------------------------------------------- /benchmarks/file/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | # SPDX-License-Identifier: BSL-1.0 3 | 4 | # Benchmarking executable. 5 | add_executable(lexy_benchmark_file) 6 | target_sources(lexy_benchmark_file PRIVATE main.cpp) 7 | target_link_libraries(lexy_benchmark_file PRIVATE foonathan::lexy::dev foonathan::lexy::file nanobench) 8 | target_compile_definitions(lexy_benchmark_file PRIVATE LEXY_INCLUDE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/../../include") 9 | set_target_properties(lexy_benchmark_file PROPERTIES OUTPUT_NAME "file") 10 | 11 | -------------------------------------------------------------------------------- /benchmarks/json/baseline.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | // SPDX-License-Identifier: BSL-1.0 3 | 4 | #include 5 | 6 | bool json_baseline(const lexy::buffer& input) 7 | { 8 | // Just do something with the input. 9 | std::size_t sum = 0; 10 | for (auto ptr = input.data(); ptr != input.data() + input.size(); ++ptr) 11 | sum += *ptr; 12 | return sum % 11 == 0; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /benchmarks/json/lexy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | // SPDX-License-Identifier: BSL-1.0 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define LEXY_TEST 9 | #include "../../examples/json.cpp" 10 | #include "../swar/swar.hpp" 11 | 12 | namespace 13 | { 14 | template 15 | struct swar_disabled_input 16 | { 17 | const lexy::buffer* _input; 18 | 19 | auto reader() const& 20 | { 21 | return swar_disabled_reader(_input->reader().position()); 22 | } 23 | }; 24 | } // namespace 25 | 26 | bool json_lexy(const lexy::buffer& input) 27 | { 28 | auto result = lexy::validate(input, lexy::noop); 29 | if (!result) 30 | throw "buggy implementation"; 31 | return result.is_success(); 32 | } 33 | 34 | bool json_lexy_no_swar(const lexy::buffer& input) 35 | { 36 | auto result = lexy::validate(swar_disabled_input{&input}, 37 | lexy::noop); 38 | if (!result) 39 | throw "buggy implementation"; 40 | return result.is_success(); 41 | } 42 | 43 | bool json_lexy_no_buffer(const lexy::buffer& input) 44 | { 45 | auto result 46 | = lexy::validate(lexy::string_input(input.data(), input.size()), lexy::noop); 47 | if (!result) 48 | throw "buggy implementation"; 49 | return result.is_success(); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /benchmarks/json/nlohmann.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | // SPDX-License-Identifier: BSL-1.0 3 | 4 | #include 5 | #include 6 | 7 | bool json_nlohmann(const lexy::buffer& input) 8 | { 9 | return nlohmann::json::accept(input.data(), input.data() + input.size()); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /benchmarks/json/pegtl.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | // SPDX-License-Identifier: BSL-1.0 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace pegtl = tao::pegtl; 10 | 11 | bool json_pegtl(const lexy::buffer& _input) 12 | { 13 | using grammar = pegtl::seq; 14 | 15 | pegtl::memory_input input(reinterpret_cast(_input.data()), _input.size(), ""); 16 | try 17 | { 18 | return pegtl::parse(input); 19 | } 20 | catch (const pegtl::parse_error&) 21 | { 22 | return false; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /benchmarks/json/rapidjson.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | // SPDX-License-Identifier: BSL-1.0 3 | 4 | #include 5 | #include 6 | 7 | bool json_rapid(const lexy::buffer& input) 8 | { 9 | rapidjson::MemoryStream stream(reinterpret_cast(input.data()), input.size()); 10 | rapidjson::BaseReaderHandler<> handler; 11 | 12 | rapidjson::Reader reader; 13 | return !reader.Parse(stream, handler).IsError(); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /benchmarks/swar/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | # SPDX-License-Identifier: BSL-1.0 3 | 4 | # Benchmarking executable. 5 | add_executable(lexy_benchmark_swar) 6 | target_sources(lexy_benchmark_swar PRIVATE main.cpp swar.hpp any.cpp delimited.cpp digits.cpp identifier.cpp literal.cpp until.cpp) 7 | target_link_libraries(lexy_benchmark_swar PRIVATE foonathan::lexy::dev foonathan::lexy::file foonathan::lexy::unicode nanobench) 8 | set_target_properties(lexy_benchmark_swar PROPERTIES OUTPUT_NAME "swar") 9 | 10 | -------------------------------------------------------------------------------- /cmake/lexyConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | # SPDX-License-Identifier: BSL-1.0 3 | 4 | # lexy CMake configuration file. 5 | 6 | @PACKAGE_INIT@ 7 | 8 | include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 9 | -------------------------------------------------------------------------------- /docs/archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /docs/archetypes/dsl.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/XXX.hpp" 3 | entities: 4 | "lexy::dsl::XXX": XXX 5 | --- 6 | :toc: left 7 | 8 | [.lead] 9 | One line description of the header. 10 | 11 | [#XXX] 12 | == Rule `lexy::dsl::XXX` 13 | 14 | {{% interface %}} 15 | ---- 16 | namespace lexy::dsl 17 | { 18 | constexpr _rule_ auto XXX; 19 | } 20 | ---- 21 | 22 | [.lead] 23 | `XXX` is a rule that does something. 24 | 25 | Requires:: 26 | Any additional requirements not seen in the interface. 27 | Matching:: 28 | Describe what is being matched and consumed without producing values. 29 | Use "match" to refer to an operation that can raise errors; 30 | "try match" to refer to an operation that cannot raise errors. 31 | Parsing:: 32 | Describe what is being matched and consumed while producing values. 33 | Use either "matching" or "parsing". 34 | Branch parsing:: 35 | Describe what differs when the rule is parsed as a branch. 36 | Use only in combination with "parsing". 37 | Errors:: 38 | * `Tag`: when this error is raised and at what position. 39 | When the error is raised can be omitted if there is only one error and it is obvious what can fail. 40 | Say the rule fails if parsing does not continue after the error. 41 | Say the rule recovers and describe what is being consumed otherwise. 42 | Values:: 43 | Describe all values that are produced. 44 | Parse tree:: 45 | If something special happens with the parse tree, mention it here. 46 | 47 | Anything else that does not fit the things above. 48 | 49 | {{% playground_example default "Some example" %}} 50 | 51 | NOTE: Any notes. 52 | 53 | -------------------------------------------------------------------------------- /docs/assets/cpp/godbolt_main.cpp: -------------------------------------------------------------------------------- 1 | //=== main function ===// 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | auto input = lexy_ext::compiler_explorer_input(); 10 | 11 | lexy::parse_tree_for tree; 12 | auto result 13 | = lexy::parse_as_tree(tree, input, lexy_ext::report_error); 14 | 15 | lexy::visualize(stdout, tree, {lexy::visualize_fancy}); 16 | 17 | if (!result) 18 | return 1; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /docs/assets/cpp/godbolt_prefix.cpp: -------------------------------------------------------------------------------- 1 | #define LEXY_HAS_UNICODE_DATABASE 1 2 | #include 3 | 4 | namespace dsl = lexy::dsl; 5 | 6 | //=== grammar ===// 7 | -------------------------------------------------------------------------------- /docs/assets/cpp/playground_headers.hpp: -------------------------------------------------------------------------------- 1 | #define LEXY_HAS_UNICODE_DATABASE 1 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | -------------------------------------------------------------------------------- /docs/assets/cpp/playground_prefix.cpp: -------------------------------------------------------------------------------- 1 | namespace dsl = lexy::dsl; 2 | #line 1 "grammar.cpp" 3 | -------------------------------------------------------------------------------- /docs/assets/css/_base.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --white: white; 3 | --background-color: #fdfdfd; 4 | --default-color: #101010; 5 | --heading-color: #0A0A0A; 6 | --link-color: #2A2A2A; 7 | --gray-highlight-color: #aaaaaa; 8 | 9 | --highlight-color: #2861ce; 10 | 11 | @media (prefers-color-scheme: dark) { 12 | --white: #202020; 13 | --background-color: #222222; 14 | --default-color: #efefef; 15 | --heading-color: #f5f5f5; 16 | --link-color: #d5d5d5; 17 | --gray-highlight-color: #555555; 18 | } 19 | } 20 | 21 | $white: var(--white); 22 | $background-color: var(--background-color); 23 | $default-color: var(--default-color); 24 | $heading-color: var(--heading-color); 25 | $link-color: var(--link-color); 26 | $highlight-color: var(--highlight-color); 27 | $gray-highlight-color: var(--gray-highlight-color); 28 | 29 | $serif-font: serif; 30 | $sans-font: sans-serif; 31 | $code-font: Inconsolata,monospace,sans-serif; 32 | 33 | $footer-offset: 75px; 34 | 35 | %limited-width { 36 | max-width: 1250px; 37 | margin: 0 auto 0 auto; 38 | padding: 0 10px 0 10px; 39 | } 40 | 41 | %content-width { 42 | @media (min-width: 800px) { 43 | max-width: 900px; 44 | padding: 0 10px 0 10px; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /docs/assets/examples/argv_input.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct production 8 | { 9 | static constexpr auto rule = LEXY_LIT("Hi"); 10 | }; 11 | 12 | //{ 13 | int main(int argc, char* argv[]) 14 | { 15 | // Create the input. 16 | lexy::argv_input input(argc, argv); 17 | 18 | // Use the input. 19 | if (!lexy::match(input)) 20 | { 21 | std::puts("Error!\n"); 22 | return 1; 23 | } 24 | } 25 | //} 26 | 27 | -------------------------------------------------------------------------------- /docs/assets/examples/argv_input.input: -------------------------------------------------------------------------------- 1 | ARGV:Hi 2 | -------------------------------------------------------------------------------- /docs/assets/examples/argv_iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //{ 5 | int main(int argc, char* argv[]) 6 | { 7 | auto begin = lexy::argv_begin(argc, argv); 8 | auto end = lexy::argv_end(argc, argv); 9 | 10 | for (auto cur = begin; cur != end; ++cur) 11 | { 12 | if (*cur == '\0') 13 | std::puts("\\0"); 14 | else 15 | std::printf("%c", *cur); 16 | } 17 | std::puts("\\0"); // last null terminator not included in the range 18 | } 19 | //} 20 | 21 | -------------------------------------------------------------------------------- /docs/assets/examples/argv_iterator.input: -------------------------------------------------------------------------------- 1 | ARGV:first second third 2 | -------------------------------------------------------------------------------- /docs/assets/examples/as_list-allocator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct state 13 | { 14 | std::allocator allocator; // The allocator that should be used. 15 | // Potentially other members here. 16 | }; 17 | 18 | struct production 19 | { 20 | static constexpr auto whitespace = dsl::ascii::space; 21 | 22 | static constexpr auto rule = [] { 23 | auto integer = dsl::integer; 24 | return dsl::list(integer, dsl::sep(dsl::comma)); 25 | }(); 26 | 27 | static constexpr auto value 28 | // Pass the allocator to the sink. 29 | = lexy::as_list>.allocator(&state::allocator); 30 | }; 31 | //} 32 | 33 | int main() 34 | { 35 | auto input = lexy_ext::compiler_explorer_input(); 36 | auto result = lexy::parse(input, state(), lexy_ext::report_error); 37 | if (!result) 38 | return 1; 39 | 40 | std::printf("numbers: "); 41 | for (auto i : result.value()) 42 | std::printf("%d ", i); 43 | std::putchar('\n'); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /docs/assets/examples/as_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct production 13 | { 14 | static constexpr auto whitespace = dsl::ascii::space; 15 | 16 | static constexpr auto rule = [] { 17 | auto integer = dsl::integer; 18 | return dsl::list(integer, dsl::sep(dsl::comma)); 19 | }(); 20 | 21 | static constexpr auto value = lexy::as_list>; 22 | }; 23 | //} 24 | 25 | int main() 26 | { 27 | auto input = lexy_ext::compiler_explorer_input(); 28 | auto result = lexy::parse(input, lexy_ext::report_error); 29 | if (!result) 30 | return 1; 31 | 32 | std::printf("numbers: "); 33 | for (auto i : result.value()) 34 | std::printf("%d ", i); 35 | std::putchar('\n'); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /docs/assets/examples/as_list.input: -------------------------------------------------------------------------------- 1 | 1, 2, 3 2 | -------------------------------------------------------------------------------- /docs/assets/examples/bind-constant.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //{ 5 | constexpr auto my_callback 6 | = lexy::callback([](int factor, int i) { return factor * i; }, 7 | [](int factor, int a, int b) { return factor * (a + b); }); 8 | 9 | // Bind all arguments. 10 | constexpr auto bound = lexy::bind(my_callback, 2, 11); 11 | //} 12 | 13 | int main() 14 | { 15 | std::printf("zero arguments: %d\n", bound()); // 2 * 11 16 | std::printf("one argument: %d\n", bound(42)); // 2 * 11 17 | } 18 | 19 | -------------------------------------------------------------------------------- /docs/assets/examples/bind-fallback.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct decimal 13 | { 14 | int integer; 15 | std::string fraction; 16 | }; 17 | 18 | struct production 19 | { 20 | struct fraction 21 | { 22 | static constexpr auto rule = dsl::capture(dsl::digits<>); 23 | static constexpr auto value = lexy::as_string; 24 | }; 25 | 26 | static constexpr auto rule = [] { 27 | auto integer = dsl::integer; 28 | 29 | return integer + dsl::opt(dsl::period >> dsl::p); 30 | }(); 31 | 32 | static constexpr auto value = lexy::bind(lexy::construct, 33 | // If the second argument is lexy::nullopt, 34 | // produce a zero instead. 35 | lexy::_1, lexy::_2 or "0"); 36 | }; 37 | //} 38 | 39 | int main() 40 | { 41 | auto input = lexy_ext::compiler_explorer_input(); 42 | auto result = lexy::parse(input, lexy_ext::report_error); 43 | if (!result) 44 | return 1; 45 | 46 | std::printf("The value is: %d.%s\n", result.value().integer, result.value().fraction.c_str()); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /docs/assets/examples/bind-fallback.input: -------------------------------------------------------------------------------- 1 | 42 2 | -------------------------------------------------------------------------------- /docs/assets/examples/bind-parse_state.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace dsl = lexy::dsl; 11 | 12 | //{ 13 | struct entry 14 | { 15 | std::string name; 16 | int a, b; 17 | }; 18 | 19 | struct production 20 | { 21 | static constexpr auto whitespace = dsl::ascii::space; 22 | 23 | static constexpr auto rule = [] { 24 | auto integer = dsl::integer; 25 | return dsl::twice(integer, dsl::sep(dsl::comma)); 26 | }(); 27 | 28 | // Construct the entry where the name is taken from the parse state. 29 | static constexpr auto value 30 | = lexy::bind(lexy::construct, lexy::parse_state, lexy::values); 31 | }; 32 | //} 33 | 34 | int main() 35 | { 36 | auto input = lexy_ext::compiler_explorer_input(); 37 | auto result = lexy::parse(input, "foo", lexy_ext::report_error); 38 | if (!result) 39 | return 1; 40 | 41 | std::printf("%s: %d, %d\n", result.value().name.c_str(), result.value().a, result.value().b); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /docs/assets/examples/bind-parse_state.input: -------------------------------------------------------------------------------- 1 | 11, 42 2 | -------------------------------------------------------------------------------- /docs/assets/examples/bind-reorder-map.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //{ 5 | constexpr auto my_callback = lexy::callback([](int a, int b) { return a - b; }); 6 | 7 | // Swap the arguments... 8 | constexpr auto bound = lexy::bind(my_callback, lexy::_2, 9 | // ... and double the (old) first one. 10 | lexy::_1.map([](int i) { return 2 * i; })); 11 | //} 12 | 13 | int main() 14 | { 15 | std::printf("result: %d\n", bound(11, 42)); // 42 - 22 16 | } 17 | 18 | -------------------------------------------------------------------------------- /docs/assets/examples/bind-values.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //{ 5 | constexpr auto my_callback 6 | = lexy::callback([](int factor, int i) { return factor * i; }, 7 | [](int factor, int a, int b) { return factor * (a + b); }); 8 | 9 | // Bind the first parameter and forward the rest unchanged. 10 | constexpr auto bound = lexy::bind(my_callback, 2, lexy::values); 11 | //} 12 | 13 | int main() 14 | { 15 | std::printf("one argument: %d\n", bound(11)); // 2 * 11 16 | std::printf("two arguments: %d\n", bound(11, 42)); // 2 * (11 + 42) 17 | } 18 | 19 | -------------------------------------------------------------------------------- /docs/assets/examples/bind_sink-parse_state.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct state 13 | { 14 | std::allocator allocator; // The allocator that should be used. 15 | // Potentially other members here. 16 | }; 17 | 18 | struct production 19 | { 20 | static constexpr auto whitespace = dsl::ascii::space; 21 | 22 | static constexpr auto rule = [] { 23 | auto integer = dsl::integer; 24 | return dsl::list(integer, dsl::sep(dsl::comma)); 25 | }(); 26 | 27 | static constexpr auto value 28 | // Pass the allocator to the sink. 29 | // Note: this is the same as the `.allocator(&state::allocator)`. 30 | = lexy::bind_sink(lexy::as_list>, 31 | lexy::parse_state.map(&state::allocator)); 32 | }; 33 | //} 34 | 35 | int main() 36 | { 37 | auto input = lexy_ext::compiler_explorer_input(); 38 | auto result = lexy::parse(input, state(), lexy_ext::report_error); 39 | if (!result) 40 | return 1; 41 | 42 | std::printf("numbers: "); 43 | for (auto i : result.value()) 44 | std::printf("%d ", i); 45 | std::putchar('\n'); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /docs/assets/examples/bits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace dsl = lexy::dsl; 7 | 8 | //{ 9 | struct code_point 10 | { 11 | static constexpr auto rule = [] { 12 | // 10xxxxxx 13 | auto continuation = dsl::bits(dsl::bit::_1, dsl::bit::_0, dsl::bit::any<6>); 14 | 15 | // 0xxxxxxx 16 | auto ascii = dsl::bits(dsl::bit::_0, dsl::bit::any<7>); 17 | // 110xxxxx 18 | auto lead_two = dsl::bits(dsl::bit::_1, dsl::bit::_1, dsl::bit::_0, dsl::bit::any<5>); 19 | // 1110xxxx 20 | auto lead_three 21 | = dsl::bits(dsl::bit::_1, dsl::bit::_1, dsl::bit::_1, dsl::bit::_0, dsl::bit::any<4>); 22 | // 11110xxx 23 | auto lead_four = dsl::bits(dsl::bit::_1, dsl::bit::_1, dsl::bit::_1, dsl::bit::_1, 24 | dsl::bit::_0, dsl::bit::any<3>); 25 | 26 | return ascii | lead_two >> continuation | lead_three >> dsl::twice(continuation) 27 | | lead_four >> dsl::times<3>(continuation); 28 | }(); 29 | }; 30 | //} 31 | 32 | struct production 33 | { 34 | static constexpr auto rule = dsl::p + dsl::eof; 35 | }; 36 | 37 | int main() 38 | { 39 | unsigned char bytes[] = {0xE2, 0x82, 0xAC}; 40 | auto input = lexy::string_input(bytes, sizeof(bytes)); 41 | 42 | auto result = lexy::validate(input, lexy_ext::report_error); 43 | return result ? 0 : 1; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /docs/assets/examples/bom.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace dsl = lexy::dsl; 7 | 8 | //{ 9 | struct production 10 | { 11 | static constexpr auto rule = [] { 12 | auto bom = dsl::bom; 15 | return dsl::opt(bom) + LEXY_LIT("Hello!") + dsl::eof; 16 | }(); 17 | }; 18 | //} 19 | 20 | int main() 21 | { 22 | const unsigned char data[] = {0xEF, 0xBB, 0xBF, 'H', 'e', 'l', 'l', 'o', '!', '\0'}; 23 | auto input = lexy::zstring_input(data); 24 | auto result = lexy::validate(input, lexy_ext::report_error); 25 | return result ? 0 : 1; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /docs/assets/examples/buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct production 9 | { 10 | static constexpr auto rule = LEXY_LIT("Hi"); 11 | }; 12 | 13 | //{ 14 | int main() 15 | { 16 | // Create a buffered input. 17 | auto input = [] { 18 | lexy::buffer::builder builder(2); 19 | builder.data()[0] = 'H'; 20 | builder.data()[1] = 'i'; 21 | return std::move(builder).finish(); 22 | }(); 23 | 24 | // Use the input. 25 | if (!lexy::match(input)) 26 | { 27 | std::puts("Error!\n"); 28 | return 1; 29 | } 30 | } 31 | //} 32 | 33 | -------------------------------------------------------------------------------- /docs/assets/examples/callback-fold.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | //{ 7 | constexpr auto my_callback = lexy::callback(lexy::fold(0, std::plus{})); 8 | //} 9 | 10 | int main() 11 | { 12 | std::printf("sum: %d\n", my_callback(1, 2, 3)); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /docs/assets/examples/callback.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //{ 5 | constexpr auto my_callback 6 | // The return type is int. 7 | = lexy::callback([](int i) { return 2 * i; }, // 8 | [](int a, int b) { return a + b; }); 9 | //} 10 | 11 | int main() 12 | { 13 | std::printf("one argument: %d\n", my_callback(11)); 14 | std::printf("two arguments: %d\n", my_callback(11, 42)); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /docs/assets/examples/capture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | // The type of a lexy::lexeme depends on the input. 13 | using lexeme = lexy_ext::compiler_explorer_lexeme; 14 | 15 | struct production 16 | { 17 | static constexpr auto rule = dsl::capture(dsl::code_point); 18 | 19 | // Same as `lexy::as_string`. 20 | static constexpr auto value = lexy::callback( 21 | [](lexeme lex) { return std::string(lex.begin(), lex.end()); }); 22 | }; 23 | //} 24 | 25 | int main() 26 | { 27 | auto input = lexy_ext::compiler_explorer_input(); 28 | auto result = lexy::parse(input, lexy_ext::report_error); 29 | if (!result) 30 | return 1; 31 | 32 | std::printf("Codepoint: %s (%zu code units)\n", result.value().c_str(), result.value().size()); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /docs/assets/examples/capture.input: -------------------------------------------------------------------------------- 1 | ü 2 | -------------------------------------------------------------------------------- /docs/assets/examples/code_point_id.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct production 13 | { 14 | static constexpr auto rule = [] { 15 | return LEXY_LIT("\\u") >> dsl::code_point_id<4> // \uXXXX 16 | | LEXY_LIT("\\U") >> dsl::code_point_id<8>; // \uXXXXXXXX 17 | }(); 18 | 19 | // Encode the resulting code point as UTF-8. 20 | static constexpr auto value = lexy::as_string; 21 | }; 22 | //} 23 | 24 | int main() 25 | { 26 | auto input = lexy_ext::compiler_explorer_input(); 27 | auto result = lexy::parse(input, lexy_ext::report_error); 28 | if (!result) 29 | return 1; 30 | 31 | std::printf("The code point is: %s\n", result.value().c_str()); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /docs/assets/examples/code_point_id.input: -------------------------------------------------------------------------------- 1 | \U0001F600 2 | -------------------------------------------------------------------------------- /docs/assets/examples/code_unit_id.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct production 13 | { 14 | // String with \xNN escape sequence. 15 | static constexpr auto rule 16 | = dsl::quoted(dsl::ascii::print, 17 | dsl::backslash_escape.rule(LEXY_LIT("x") 18 | >> dsl::code_unit_id)); 19 | 20 | static constexpr auto value = lexy::as_string; 21 | }; 22 | //} 23 | 24 | int main() 25 | { 26 | auto input = lexy_ext::compiler_explorer_input(); 27 | auto result = lexy::parse(input, lexy_ext::report_error); 28 | if (!result) 29 | return 1; 30 | 31 | std::printf("The code point is: %s\n", result.value().c_str()); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /docs/assets/examples/code_unit_id.input: -------------------------------------------------------------------------------- 1 | "Hello, \x41!" 2 | -------------------------------------------------------------------------------- /docs/assets/examples/color.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace 9 | { 10 | struct Color 11 | { 12 | std::uint8_t r, g, b; 13 | }; 14 | 15 | namespace grammar 16 | { 17 | namespace dsl = lexy::dsl; 18 | 19 | struct channel 20 | { 21 | static constexpr auto rule = dsl::integer(dsl::n_digits<2, dsl::hex>); 22 | static constexpr auto value = lexy::forward; 23 | }; 24 | 25 | struct color 26 | { 27 | static constexpr auto rule = dsl::hash_sign + dsl::times<3>(dsl::p); 28 | static constexpr auto value = lexy::construct; 29 | }; 30 | } // namespace grammar 31 | } // namespace 32 | 33 | int main() 34 | { 35 | auto input = lexy_ext::compiler_explorer_input(); // special input for CompilerExplorer examples 36 | auto result = lexy::parse(input, lexy_ext::report_error); 37 | if (result.has_value()) 38 | { 39 | auto color = result.value(); 40 | std::printf("#%02x%02x%02x\n", color.r, color.g, color.b); 41 | } 42 | 43 | return result ? 0 : 1; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /docs/assets/examples/color.input: -------------------------------------------------------------------------------- 1 | #FF00FF 2 | -------------------------------------------------------------------------------- /docs/assets/examples/compose-callback.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //{ 6 | constexpr auto my_strlen 7 | // Construct a string, then return its size. 8 | = lexy::as_string | lexy::callback(&std::string::size); 9 | //} 10 | 11 | int main() 12 | { 13 | std::printf("length: %zu\n", my_strlen("Hello")); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /docs/assets/examples/compose-sink.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace dsl = lexy::dsl; 11 | 12 | //{ 13 | struct entry 14 | { 15 | std::string name; 16 | std::vector numbers; 17 | }; 18 | 19 | struct production 20 | { 21 | static constexpr auto whitespace = dsl::ascii::space; 22 | 23 | static constexpr auto rule = [] { 24 | auto integer = dsl::integer; 25 | return dsl::square_bracketed.list(integer, dsl::sep(dsl::comma)); 26 | }(); 27 | 28 | static constexpr auto value 29 | // Collect all the numbers in a vector, then turn the result into an entry. 30 | = lexy::as_list> >> lexy::callback([](std::vector&& vec) { 31 | return entry{"foo", std::move(vec)}; 32 | }); 33 | }; 34 | //} 35 | 36 | int main() 37 | { 38 | auto input = lexy_ext::compiler_explorer_input(); 39 | auto result = lexy::parse(input, lexy_ext::report_error); 40 | if (!result) 41 | return 1; 42 | 43 | std::printf("%s: ", result.value().name.c_str()); 44 | for (auto i : result.value().numbers) 45 | std::printf("%d ", i); 46 | std::putchar('\n'); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /docs/assets/examples/compose-sink.input: -------------------------------------------------------------------------------- 1 | [1, 2, 3] 2 | -------------------------------------------------------------------------------- /docs/assets/examples/concat.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct list 13 | { 14 | static constexpr auto rule = [] { 15 | auto integer = dsl::integer; 16 | return dsl::list(integer, dsl::sep(dsl::comma)); 17 | }(); 18 | 19 | static constexpr auto value = lexy::as_list>; 20 | }; 21 | 22 | struct production 23 | { 24 | static constexpr auto whitespace = dsl::ascii::space; 25 | static constexpr auto rule = dsl::list(dsl::p, dsl::sep(dsl::newline)); 26 | static constexpr auto value = lexy::concat>; 27 | }; 28 | //} 29 | 30 | int main() 31 | { 32 | auto input = lexy_ext::compiler_explorer_input(); 33 | auto result = lexy::parse(input, lexy_ext::report_error); 34 | if (!result) 35 | return 1; 36 | 37 | std::printf("numbers: "); 38 | for (auto i : result.value()) 39 | std::printf("%d ", i); 40 | std::putchar('\n'); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /docs/assets/examples/concat.input: -------------------------------------------------------------------------------- 1 | 1, 2, 3 2 | 4, 5, 6 3 | 7, 8, 9 4 | -------------------------------------------------------------------------------- /docs/assets/examples/flags.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | enum class cv_qualifier 11 | { 12 | none = 0, 13 | const_ = 1 << 1, 14 | volatile_ = 1 << 2, 15 | }; 16 | 17 | struct production 18 | { 19 | static constexpr auto whitespace = dsl::ascii::space; 20 | 21 | // Map cv-qualifiers to their value. 22 | static constexpr auto cv = lexy::symbol_table // 23 | .map(cv_qualifier::const_) 24 | .map(cv_qualifier::volatile_); 25 | 26 | // Parse any combination of cv qualifiers. 27 | static constexpr auto rule = dsl::flags(dsl::symbol(dsl::identifier(dsl::ascii::alpha))); 28 | 29 | static constexpr auto value = lexy::forward; 30 | }; 31 | //} 32 | 33 | int main() 34 | { 35 | auto input = lexy_ext::compiler_explorer_input(); 36 | auto result = lexy::parse(input, lexy_ext::report_error); 37 | if (!result) 38 | return 1; 39 | 40 | if ((int(result.value()) & int(cv_qualifier::const_)) != 0) 41 | std::puts("const"); 42 | if ((int(result.value()) & int(cv_qualifier::volatile_)) != 0) 43 | std::puts("volatile"); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /docs/assets/examples/flags.input: -------------------------------------------------------------------------------- 1 | const volatile 2 | -------------------------------------------------------------------------------- /docs/assets/examples/fold.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct production 11 | { 12 | static constexpr auto whitespace = dsl::ascii::space; 13 | 14 | static constexpr auto rule = [] { 15 | // An item is a point (x, y) 16 | auto integer = dsl::integer; 17 | auto item = dsl::parenthesized(dsl::twice(integer, dsl::sep(dsl::comma))); 18 | 19 | return dsl::list(item, dsl::sep(dsl::comma)); 20 | }(); 21 | 22 | // Sum the x components of the points. 23 | static constexpr auto value 24 | = lexy::fold(0, [](int current, int x, int) { return current + x; }); 25 | }; 26 | //} 27 | 28 | int main() 29 | { 30 | auto input = lexy_ext::compiler_explorer_input(); 31 | auto result = lexy::parse(input, lexy_ext::report_error); 32 | if (!result) 33 | return 1; 34 | 35 | std::printf("The value is: %d\n", result.value()); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /docs/assets/examples/fold.input: -------------------------------------------------------------------------------- 1 | (1, 1), (11, -5), (8, 0) 2 | -------------------------------------------------------------------------------- /docs/assets/examples/fold_inplace.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct production 13 | { 14 | static constexpr auto whitespace = dsl::ascii::space; 15 | 16 | static constexpr auto rule = [] { 17 | auto integer = dsl::integer; 18 | 19 | return dsl::list(integer, dsl::sep(dsl::comma)); 20 | }(); 21 | 22 | // Construct a `std::deque` in reverse order. 23 | static constexpr auto value 24 | = lexy::fold_inplace>(std::initializer_list{}, 25 | [](auto& deque, int i) { deque.push_front(i); }); 26 | }; 27 | //} 28 | 29 | int main() 30 | { 31 | auto input = lexy_ext::compiler_explorer_input(); 32 | auto result = lexy::parse(input, lexy_ext::report_error); 33 | if (!result) 34 | return 1; 35 | 36 | std::printf("numbers: "); 37 | for (auto i : result.value()) 38 | std::printf("%d ", i); 39 | std::putchar('\n'); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /docs/assets/examples/fold_inplace.input: -------------------------------------------------------------------------------- 1 | 1, 2, 3 2 | -------------------------------------------------------------------------------- /docs/assets/examples/identifier_case_folded.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct production 13 | { 14 | static constexpr auto rule = dsl::identifier(dsl::ascii::alpha); 15 | 16 | static constexpr auto value 17 | = lexy::as_string.case_folding(dsl::ascii::case_folding); 18 | }; 19 | //} 20 | 21 | int main() 22 | { 23 | auto input = lexy_ext::compiler_explorer_input(); 24 | auto result = lexy::parse(input, lexy_ext::report_error); 25 | if (!result) 26 | return 1; 27 | 28 | std::printf("Codepoint: %s (%zu code units)\n", result.value().c_str(), result.value().size()); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /docs/assets/examples/identifier_case_folded.input: -------------------------------------------------------------------------------- 1 | HeLlO 2 | -------------------------------------------------------------------------------- /docs/assets/examples/integer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct production 11 | { 12 | static constexpr auto rule = [] { 13 | auto digits = dsl::digits<>.sep(dsl::digit_sep_tick).no_leading_zero(); 14 | return dsl::integer(digits); 15 | }(); 16 | 17 | static constexpr auto value = lexy::as_integer; 18 | }; 19 | //} 20 | 21 | int main() 22 | { 23 | auto input = lexy_ext::compiler_explorer_input(); 24 | auto result = lexy::parse(input, lexy_ext::report_error); 25 | if (!result.has_value()) 26 | return 1; 27 | 28 | std::printf("The value is: %d\n", result.value()); 29 | return result ? 0 : 1; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /docs/assets/examples/integer.input: -------------------------------------------------------------------------------- 1 | 4'294'967'295 2 | -------------------------------------------------------------------------------- /docs/assets/examples/list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct production 13 | { 14 | static constexpr auto rule = [] { 15 | auto item = dsl::capture(dsl::ascii::alpha); 16 | return dsl::list(item); 17 | }(); 18 | 19 | // Same as `lexy::as_string`. 20 | static constexpr auto value 21 | = lexy::fold_inplace("", [](std::string& result, auto lexeme) { 22 | result.append(lexeme.begin(), lexeme.end()); 23 | }); 24 | }; 25 | //} 26 | 27 | int main() 28 | { 29 | auto input = lexy_ext::compiler_explorer_input(); 30 | auto result = lexy::parse(input, lexy_ext::report_error); 31 | if (!result.has_value()) 32 | return 1; 33 | 34 | std::printf("The list is: %s\n", result.value().c_str()); 35 | return result ? 0 : 1; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /docs/assets/examples/list.input: -------------------------------------------------------------------------------- 1 | abc 2 | -------------------------------------------------------------------------------- /docs/assets/examples/list_sep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct production 13 | { 14 | static constexpr auto rule = [] { 15 | auto item = dsl::capture(dsl::ascii::alpha); 16 | auto sep = dsl::sep(dsl::comma); 17 | return dsl::list(item, sep); 18 | }(); 19 | 20 | static constexpr auto value = lexy::as_string; 21 | }; 22 | //} 23 | 24 | int main() 25 | { 26 | auto input = lexy_ext::compiler_explorer_input(); 27 | auto result = lexy::parse(input, lexy_ext::report_error); 28 | if (!result.has_value()) 29 | return 1; 30 | 31 | std::printf("The list is: %s\n", result.value().c_str()); 32 | return result ? 0 : 1; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /docs/assets/examples/list_sep.input: -------------------------------------------------------------------------------- 1 | a,b,c, 2 | -------------------------------------------------------------------------------- /docs/assets/examples/lookahead.input: -------------------------------------------------------------------------------- 1 | // INPUT:foo=42 2 | -------------------------------------------------------------------------------- /docs/assets/examples/make_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct production 9 | { 10 | static constexpr auto rule = LEXY_LIT("Hi"); 11 | }; 12 | 13 | struct file_span 14 | { 15 | const void* memory; 16 | std::size_t size; 17 | }; 18 | 19 | file_span map_file(const char* /* path */) 20 | { 21 | // fake something 22 | static constexpr unsigned char memory[] = {'H', 0x00, 'i', 0x00}; 23 | return {memory, 4}; 24 | } 25 | 26 | //{ 27 | int main() 28 | { 29 | // Map a file into memory. 30 | auto span = map_file("input.txt"); 31 | 32 | // Treat the file as little endian UTF-16. 33 | constexpr auto make_utf16_le 34 | = lexy::make_buffer_from_raw; 35 | auto input = make_utf16_le(span.memory, span.size); 36 | 37 | // Use the input. 38 | if (!lexy::match(input)) 39 | { 40 | std::puts("Error!\n"); 41 | return 1; 42 | } 43 | } 44 | //} 45 | 46 | -------------------------------------------------------------------------------- /docs/assets/examples/member.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct point 11 | { 12 | int x, y; 13 | }; 14 | 15 | struct production 16 | { 17 | static constexpr auto rule = [] { 18 | auto value = dsl::integer; 19 | 20 | // Parse an integer into the x/y member of point. 21 | auto x_coord = (dsl::member<& point::x> = value); 22 | auto y_coord = (dsl::member<& point::y> = value); 23 | 24 | return x_coord + dsl::comma + y_coord; 25 | }(); 26 | 27 | // `lexy::as_aggregate` accepts the `lexy::member` + value pairs. 28 | static constexpr auto value = lexy::as_aggregate; 29 | }; 30 | //} 31 | 32 | int main() 33 | { 34 | auto input = lexy_ext::compiler_explorer_input(); 35 | auto result = lexy::parse(input, lexy_ext::report_error); 36 | if (!result) 37 | return 1; 38 | 39 | std::printf("The value is: (%d, %d)\n", result.value().x, result.value().y); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /docs/assets/examples/member.input: -------------------------------------------------------------------------------- 1 | 42,11 2 | -------------------------------------------------------------------------------- /docs/assets/examples/new.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct point 13 | { 14 | int x, y; 15 | }; 16 | 17 | struct production 18 | { 19 | static constexpr auto whitespace = dsl::ascii::space; 20 | 21 | static constexpr auto rule = [] { 22 | auto integer = dsl::integer; 23 | return dsl::twice(integer, dsl::sep(dsl::comma)); 24 | }(); 25 | static constexpr auto value = lexy::new_>; 26 | }; 27 | //} 28 | 29 | int main() 30 | { 31 | auto input = lexy_ext::compiler_explorer_input(); 32 | auto result = lexy::parse(input, lexy_ext::report_error); 33 | if (!result) 34 | return 1; 35 | 36 | std::printf("The value is: (%d, %d)\n", result.value()->x, result.value()->y); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /docs/assets/examples/new.input: -------------------------------------------------------------------------------- 1 | 11, 42 2 | -------------------------------------------------------------------------------- /docs/assets/examples/noop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | struct production 10 | { 11 | static constexpr auto rule = dsl::integer; 12 | static constexpr auto value = lexy::forward; 13 | }; 14 | 15 | //{ 16 | int main() 17 | { 18 | auto input = lexy_ext::compiler_explorer_input(); 19 | 20 | // Parse the production, but ignore all errors. 21 | auto result = lexy::parse(input, lexy::noop); 22 | if (!result) 23 | // Note that parsing can still fail. 24 | return 1; 25 | 26 | std::printf("The value is: %d\n", result.value()); 27 | } 28 | //} 29 | 30 | -------------------------------------------------------------------------------- /docs/assets/examples/op-basic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct production : lexy::expression_production 11 | { 12 | static constexpr auto atom = dsl::integer; 13 | 14 | struct operation : dsl::infix_op_left 15 | { 16 | static constexpr auto op = dsl::op(dsl::lit_c<'+'>); 17 | using operand = dsl::atom; 18 | }; 19 | 20 | static constexpr auto value 21 | = lexy::callback([](int value) { return value; }, 22 | [](int lhs, lexy::op, int rhs) { return lhs + rhs; }); 23 | }; 24 | //} 25 | 26 | int main() 27 | { 28 | auto input = lexy_ext::compiler_explorer_input(); 29 | auto result = lexy::parse(input, lexy_ext::report_error); 30 | if (!result) 31 | return 1; 32 | 33 | std::printf("Result: %d\n", result.value()); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /docs/assets/examples/op-basic.input: -------------------------------------------------------------------------------- 1 | 1+2 2 | -------------------------------------------------------------------------------- /docs/assets/examples/op-choice.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | constexpr auto op_plus = dsl::op(dsl::lit_c<'+'>); 11 | constexpr auto op_minus = dsl::op(dsl::lit_c<'-'>); 12 | 13 | struct production : lexy::expression_production 14 | { 15 | static constexpr auto atom = dsl::integer; 16 | 17 | struct operation : dsl::infix_op_left 18 | { 19 | static constexpr auto op = op_plus / op_minus; 20 | using operand = dsl::atom; 21 | }; 22 | 23 | static constexpr auto value 24 | = lexy::callback([](int value) { return value; }, 25 | [](int lhs, lexy::op, int rhs) { return lhs + rhs; }, 26 | [](int lhs, lexy::op, int rhs) { return lhs - rhs; }); 27 | }; 28 | //} 29 | 30 | int main() 31 | { 32 | auto input = lexy_ext::compiler_explorer_input(); 33 | auto result = lexy::parse(input, lexy_ext::report_error); 34 | if (!result) 35 | return 1; 36 | 37 | std::printf("Result: %d\n", result.value()); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /docs/assets/examples/op-choice.input: -------------------------------------------------------------------------------- 1 | 1-2 2 | -------------------------------------------------------------------------------- /docs/assets/examples/op-custom.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct plus 11 | { 12 | const LEXY_CHAR8_T* pos; 13 | 14 | constexpr plus(const LEXY_CHAR8_T* pos) : pos(pos) {} 15 | }; 16 | 17 | struct production : lexy::expression_production 18 | { 19 | static constexpr auto atom = dsl::integer; 20 | 21 | struct operation : dsl::infix_op_left 22 | { 23 | static constexpr auto op = dsl::op(dsl::lit_c<'+'>); 24 | using operand = dsl::atom; 25 | }; 26 | 27 | static constexpr auto value = lexy::callback([](int value) { return value; }, 28 | [](int lhs, plus op, int rhs) { 29 | LEXY_PRECONDITION(*op.pos == '+'); 30 | return lhs + rhs; 31 | }); 32 | }; 33 | //} 34 | 35 | int main() 36 | { 37 | auto input = lexy_ext::compiler_explorer_input(); 38 | auto result = lexy::parse(input, lexy_ext::report_error); 39 | if (!result) 40 | return 1; 41 | 42 | std::printf("Result: %d\n", result.value()); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /docs/assets/examples/op-custom.input: -------------------------------------------------------------------------------- 1 | 1+2 2 | -------------------------------------------------------------------------------- /docs/assets/examples/opt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace dsl = lexy::dsl; 11 | 12 | //{ 13 | struct decimal 14 | { 15 | int integer; 16 | std::optional fraction; 17 | }; 18 | 19 | struct production 20 | { 21 | struct fraction 22 | { 23 | static constexpr auto rule = dsl::capture(dsl::digits<>); 24 | static constexpr auto value = lexy::as_string; 25 | }; 26 | 27 | static constexpr auto rule = [] { 28 | auto integer = dsl::integer; 29 | 30 | return integer + dsl::opt(dsl::period >> dsl::p); 31 | }(); 32 | 33 | static constexpr auto value = lexy::construct; 34 | }; 35 | //} 36 | 37 | int main() 38 | { 39 | auto input = lexy_ext::compiler_explorer_input(); 40 | auto result = lexy::parse(input, lexy_ext::report_error); 41 | if (!result) 42 | return 1; 43 | 44 | std::printf("The value is: %d.%s\n", result.value().integer, 45 | result.value().fraction.value_or("0").c_str()); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /docs/assets/examples/opt.input: -------------------------------------------------------------------------------- 1 | 3.14 2 | -------------------------------------------------------------------------------- /docs/assets/examples/parse_tree_parsing.input: -------------------------------------------------------------------------------- 1 | value = 123 2 | -------------------------------------------------------------------------------- /docs/assets/examples/point.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct point 11 | { 12 | int x, y; 13 | }; 14 | 15 | struct production 16 | { 17 | static constexpr auto whitespace = dsl::ascii::space; 18 | 19 | static constexpr auto rule = [] { 20 | auto integer = dsl::integer; 21 | return dsl::twice(integer, dsl::sep(dsl::comma)); 22 | }(); 23 | static constexpr auto value = lexy::construct; 24 | }; 25 | //} 26 | 27 | int main() 28 | { 29 | auto input = lexy_ext::compiler_explorer_input(); 30 | auto result = lexy::parse(input, lexy_ext::report_error); 31 | if (!result) 32 | return 1; 33 | 34 | std::printf("The value is: (%d, %d)\n", result.value().x, result.value().y); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /docs/assets/examples/point.input: -------------------------------------------------------------------------------- 1 | 11, 42 2 | -------------------------------------------------------------------------------- /docs/assets/examples/quoted_escape.input: -------------------------------------------------------------------------------- 1 | "Hello\nWorld\u0021" 2 | -------------------------------------------------------------------------------- /docs/assets/examples/range_input.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct production 9 | { 10 | static constexpr auto rule = LEXY_LIT("Hi"); 11 | }; 12 | 13 | //{ 14 | int main() 15 | { 16 | std::list list{u'H', u'i'}; 17 | 18 | // Create the input, deducing the encoding. 19 | auto input = lexy::range_input(list.begin(), list.end()); 20 | 21 | // Use the input. 22 | if (!lexy::match(input)) 23 | { 24 | std::puts("Error!\n"); 25 | return 1; 26 | } 27 | } 28 | //} 29 | 30 | -------------------------------------------------------------------------------- /docs/assets/examples/scan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace dsl = lexy::dsl; 7 | 8 | //{ 9 | struct control_production 10 | { 11 | // Allow ASCII whitespace. 12 | static constexpr auto whitespace = dsl::ascii::space; 13 | }; 14 | 15 | int main() 16 | { 17 | // Construct a scanner for the input. 18 | auto input = lexy_ext::compiler_explorer_input(); 19 | auto scanner = lexy::scan(input, lexy_ext::report_error); 20 | 21 | // Parse two integers separated by comma. 22 | auto x = scanner.integer(dsl::digits<>); 23 | scanner.parse(dsl::comma); 24 | auto y = scanner.integer(dsl::digits<>); 25 | 26 | std::printf("%d, %d", x.value_or(-1), y.value_or(-1)); 27 | } 28 | //} 29 | 30 | -------------------------------------------------------------------------------- /docs/assets/examples/scan.input: -------------------------------------------------------------------------------- 1 | 11, 42 2 | -------------------------------------------------------------------------------- /docs/assets/examples/sign.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct production 11 | { 12 | // Sign followed by a decimal integer. 13 | static constexpr auto rule = dsl::sign + dsl::integer; 14 | static constexpr auto value = lexy::as_integer; 15 | }; 16 | //} 17 | 18 | int main() 19 | { 20 | auto input = lexy_ext::compiler_explorer_input(); 21 | auto result = lexy::parse(input, lexy_ext::report_error); 22 | if (!result.has_value()) 23 | return 1; 24 | 25 | std::printf("The value is: %d\n", result.value()); 26 | return result ? 0 : 1; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /docs/assets/examples/sign.input: -------------------------------------------------------------------------------- 1 | -123 2 | -------------------------------------------------------------------------------- /docs/assets/examples/string_input.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct production 8 | { 9 | static constexpr auto rule = LEXY_LIT("Hi"); 10 | }; 11 | 12 | //{ 13 | int main() 14 | { 15 | unsigned char array[] = {'H', 'i'}; 16 | 17 | // Create the input, deducing the encoding. 18 | auto input = lexy::string_input(array, array + 2); 19 | 20 | // Use the input. 21 | if (!lexy::match(input)) 22 | { 23 | std::puts("Error!\n"); 24 | return 1; 25 | } 26 | } 27 | //} 28 | 29 | -------------------------------------------------------------------------------- /docs/assets/examples/symbol.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct production 11 | { 12 | // Map names of the entities to their replacement value. 13 | static constexpr auto entities = lexy::symbol_table 14 | .map('"') 15 | .map('&') 16 | .map('\'') 17 | .map('<') 18 | .map('>'); 19 | 20 | static constexpr auto rule = [] { 21 | auto name = dsl::identifier(dsl::ascii::alpha); 22 | auto reference = dsl::symbol(name); 23 | return dsl::lit_c<'&'> >> reference + dsl::lit_c<';'>; 24 | }(); 25 | 26 | static constexpr auto value = lexy::forward; 27 | }; 28 | //} 29 | 30 | int main() 31 | { 32 | auto input = lexy_ext::compiler_explorer_input(); 33 | auto result = lexy::parse(input, lexy_ext::report_error); 34 | if (!result) 35 | return 1; 36 | 37 | std::printf("The replacement is: '%c'\n", result.value()); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /docs/assets/examples/symbol.input: -------------------------------------------------------------------------------- 1 | < 2 | -------------------------------------------------------------------------------- /docs/assets/examples/times_isep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct three_ints 11 | { 12 | static constexpr auto rule = [] { 13 | auto item = dsl::integer; 14 | auto sep = dsl::ignore_trailing_sep(dsl::comma); 15 | return dsl::times<3>(item, sep) + dsl::eof; 16 | }(); 17 | 18 | static constexpr auto value 19 | = lexy::callback([](int a, int b, int c) { return a + b + c; }); 20 | }; 21 | 22 | struct production 23 | { 24 | static constexpr auto rule = dsl::p + dsl::comma + dsl::p; 25 | static constexpr auto value = lexy::callback([](int a, int b) { return a + b; }); 26 | }; 27 | //} 28 | 29 | int main() 30 | { 31 | auto input = lexy_ext::compiler_explorer_input(); 32 | auto result = lexy::parse(input, lexy_ext::report_error); 33 | if (!result) 34 | return 1; 35 | 36 | std::printf("The sum is: %d\n", result.value()); 37 | } 38 | -------------------------------------------------------------------------------- /docs/assets/examples/times_isep.input: -------------------------------------------------------------------------------- 1 | 1,2,3,4,5,6 2 | -------------------------------------------------------------------------------- /docs/assets/examples/times_tsep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct production 11 | { 12 | static constexpr auto rule = [] { 13 | auto item = dsl::integer; 14 | auto sep = dsl::trailing_sep(dsl::comma); 15 | return dsl::times<3>(item, sep); 16 | }(); 17 | 18 | static constexpr auto value 19 | = lexy::callback([](int a, int b, int c) { return a + b + c; }); 20 | }; 21 | //} 22 | 23 | int main() 24 | { 25 | auto input = lexy_ext::compiler_explorer_input(); 26 | auto result = lexy::parse(input, lexy_ext::report_error); 27 | if (!result) 28 | return 1; 29 | 30 | std::printf("The sum is: %d\n", result.value()); 31 | } 32 | -------------------------------------------------------------------------------- /docs/assets/examples/times_tsep.input: -------------------------------------------------------------------------------- 1 | 1,2,3, 2 | -------------------------------------------------------------------------------- /docs/assets/examples/token_kind_map.input: -------------------------------------------------------------------------------- 1 | Hello World! 2 | -------------------------------------------------------------------------------- /docs/assets/examples/true_false.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | //{ 10 | struct boolean 11 | { 12 | struct true_ 13 | { 14 | static constexpr auto rule = LEXY_LIT("true"); 15 | // Produce the value `true`. 16 | static constexpr auto value = lexy::constant(true); 17 | }; 18 | struct false_ 19 | { 20 | static constexpr auto rule = LEXY_LIT("false"); 21 | // Produce the value `false`. 22 | static constexpr auto value = lexy::constant(false); 23 | }; 24 | 25 | static constexpr auto rule = dsl::p | dsl::p; 26 | // Both rules produce a boolean value, just forward that one. 27 | static constexpr auto value = lexy::forward; 28 | }; 29 | //} 30 | 31 | int main() 32 | { 33 | auto input = lexy_ext::compiler_explorer_input(); 34 | 35 | auto result = lexy::parse(input, lexy_ext::report_error); 36 | if (!result) 37 | return 1; 38 | 39 | std::printf("The value is: %d\n", static_cast(result.value())); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /docs/assets/examples/true_false.input: -------------------------------------------------------------------------------- 1 | true 2 | -------------------------------------------------------------------------------- /docs/assets/examples/try.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsl = lexy::dsl; 10 | 11 | //{ 12 | struct version 13 | { 14 | std::optional major, minor, patch; 15 | }; 16 | 17 | struct production 18 | { 19 | static constexpr auto rule = [] { 20 | // If we don't have an integer, recover by producing nullopt. 21 | auto number = dsl::try_(dsl::integer, dsl::nullopt); 22 | auto dot = dsl::try_(dsl::period); 23 | return number + dot + number + dot + number; 24 | }(); 25 | 26 | static constexpr auto value = lexy::construct; 27 | }; 28 | //} 29 | 30 | int main() 31 | { 32 | auto input = lexy_ext::compiler_explorer_input(); 33 | auto result = lexy::parse(input, lexy_ext::report_error); 34 | if (!result.has_value()) 35 | return 1; 36 | 37 | auto [major, minor, patch] = result.value(); 38 | std::printf("The value is: %d.%d.%d\n", major.value_or(0), minor.value_or(0), 39 | patch.value_or(0)); 40 | return result ? 0 : 1; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /docs/assets/examples/try.input: -------------------------------------------------------------------------------- 1 | 1.0 2 | -------------------------------------------------------------------------------- /docs/assets/examples/visualize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dsl = lexy::dsl; 8 | 9 | struct name 10 | { 11 | static constexpr auto rule 12 | // One or more alpha numeric characters, underscores or hyphens. 13 | = dsl::identifier(dsl::ascii::alnum / dsl::lit_c<'_'> / dsl::lit_c<'-'>); 14 | }; 15 | 16 | struct production 17 | { 18 | // Allow arbitrary spaces between individual tokens. 19 | // Note that this includes the individual characters of the name. 20 | static constexpr auto whitespace = dsl::ascii::space; 21 | 22 | static constexpr auto rule = [] { 23 | auto greeting = LEXY_LIT("Hello"); 24 | return greeting + dsl::p + dsl::exclamation_mark + dsl::eof; 25 | }(); 26 | }; 27 | 28 | //{ 29 | int main() 30 | { 31 | auto input = lexy_ext::compiler_explorer_input(); 32 | 33 | lexy::parse_tree_for tree; 34 | auto result = lexy::parse_as_tree(tree, input, lexy_ext::report_error); 35 | 36 | lexy::visualize(stdout, tree, {lexy::visualize_fancy}); 37 | 38 | if (!result) 39 | return 1; 40 | } 41 | //} 42 | 43 | -------------------------------------------------------------------------------- /docs/assets/examples/visualize.input: -------------------------------------------------------------------------------- 1 | Hello World! 2 | -------------------------------------------------------------------------------- /docs/assets/examples/zstring_input.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct production 9 | { 10 | static constexpr auto rule = LEXY_LIT("Hi"); 11 | }; 12 | 13 | //{ 14 | int main() 15 | { 16 | // Create the input, deducing the encoding. 17 | auto input = lexy::zstring_input("Hi"); 18 | 19 | // Use the input. 20 | if (!lexy::match(input)) 21 | { 22 | std::puts("Error!\n"); 23 | return 1; 24 | } 25 | } 26 | //} 27 | 28 | -------------------------------------------------------------------------------- /docs/assets/icons/arrow-left.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/assets/icons/arrow-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/icons/arrow-up.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/assets/icons/beta.svg: -------------------------------------------------------------------------------- 1 | 2 | Experimental 3 | 4 | -------------------------------------------------------------------------------- /docs/assets/icons/bug.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/icons/calender.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/icons/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/icons/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/icons/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/icons/license.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/icons/play.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "*": [ 6 | "*" 7 | ] 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /docs/assets/playground/any.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Literally anything you want. 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::any; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /docs/assets/playground/case_folding.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:HeLlO wOrLd! 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::ascii::case_folding(LEXY_LIT("hello world!")); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/char_class_intersection.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:" " 2 | struct production 3 | { 4 | static constexpr auto rule // 5 | = dsl::quoted(dsl::ascii::space & dsl::ascii::print); 6 | }; 7 | -------------------------------------------------------------------------------- /docs/assets/playground/char_class_macro.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:atom 2 | struct production 3 | { 4 | static constexpr auto atext 5 | = LEXY_CHAR_CLASS("atext", 6 | dsl::ascii::alpha / dsl::ascii::digit / LEXY_LIT("!") / LEXY_LIT("#") 7 | / LEXY_LIT("$") / LEXY_LIT("%") / LEXY_LIT("&") / LEXY_LIT("'") 8 | / LEXY_LIT("*") / LEXY_LIT("+") / LEXY_LIT("-") / LEXY_LIT("/") 9 | / LEXY_LIT("=") / LEXY_LIT("?") / LEXY_LIT("^") / LEXY_LIT("_") 10 | / LEXY_LIT("`") / LEXY_LIT("{") / LEXY_LIT("|") / LEXY_LIT("}")); 11 | 12 | static constexpr auto rule = dsl::identifier(atext); 13 | }; 14 | -------------------------------------------------------------------------------- /docs/assets/playground/char_class_minus.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:ABX 2 | struct production 3 | { 4 | static constexpr auto rule // 5 | = dsl::identifier(dsl::ascii::upper - dsl::lit_c<'X'>); 6 | }; 7 | -------------------------------------------------------------------------------- /docs/assets/playground/char_class_union.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:H123 2 | struct production 3 | { 4 | static constexpr auto rule // 5 | = dsl::identifier(dsl::ascii::upper / dsl::ascii::digit); 6 | }; 7 | -------------------------------------------------------------------------------- /docs/assets/playground/choice.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("Hello") | LEXY_LIT("Hi"); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/choice_bad.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:ab 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("a") | LEXY_LIT("ab"); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/choice_branch.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:ab 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("a") >> LEXY_LIT("bc") // a, then bc 5 | | LEXY_LIT("a") >> LEXY_LIT("b") // a, then b 6 | | LEXY_LIT("bc") | LEXY_LIT("b"); 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/choice_else.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hallo 2 | struct production 3 | { 4 | static constexpr auto rule 5 | // Input should be empty if greeting isn't known. 6 | = LEXY_LIT("Hello") | LEXY_LIT("Hi") | dsl::else_ >> dsl::eof; 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/choice_error.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hallo 2 | struct production 3 | { 4 | struct unknown_greeting 5 | { 6 | static constexpr auto name = "unknown greeting"; 7 | }; 8 | 9 | static constexpr auto rule 10 | // Generate a custom error for an unknown greeting. 11 | = LEXY_LIT("Hello") | LEXY_LIT("Hi") | dsl::error; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/choice_error_range.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hallo 2 | struct production 3 | { 4 | struct unknown_greeting 5 | { 6 | static constexpr auto name = "unknown greeting"; 7 | }; 8 | 9 | static constexpr auto rule 10 | // Generate a custom error for an unknown greeting. 11 | = LEXY_LIT("Hello") | LEXY_LIT("Hi") 12 | | dsl::error(dsl::while_(dsl::ascii::alpha)); 13 | }; 14 | -------------------------------------------------------------------------------- /docs/assets/playground/choice_production.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:type Id = Integer; 2 | constexpr auto id = dsl::identifier(dsl::ascii::alpha); 3 | constexpr auto kw_function = LEXY_KEYWORD("function", id); 4 | constexpr auto kw_type = LEXY_KEYWORD("type", id); 5 | 6 | struct function_decl 7 | { 8 | static constexpr auto rule = [] { 9 | auto arguments = dsl::parenthesized(LEXY_LIT("...")); 10 | auto body = dsl::curly_bracketed(LEXY_LIT("...")); 11 | 12 | return kw_function >> id + arguments + body; 13 | }(); 14 | }; 15 | 16 | struct type_decl 17 | { 18 | static constexpr auto rule // 19 | = kw_type >> id + dsl::lit_c<'='> + id + dsl::semicolon; 20 | }; 21 | 22 | struct production 23 | { 24 | static constexpr auto whitespace = dsl::ascii::space; 25 | static constexpr auto rule = dsl::p | dsl::p; 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /docs/assets/playground/code_point.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:a 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::code_point + dsl::eof; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/code_point_if.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:a 2 | struct production 3 | { 4 | struct even 5 | { 6 | constexpr bool operator()(lexy::code_point cp) 7 | { 8 | return cp.value() % 2 == 0; 9 | } 10 | }; 11 | 12 | static constexpr auto rule = dsl::code_point.if_() + dsl::eof; 13 | }; 14 | -------------------------------------------------------------------------------- /docs/assets/playground/color.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:#FF00FF 2 | struct channel 3 | { 4 | static constexpr auto rule = dsl::n_digits<2, dsl::hex>; 5 | }; 6 | 7 | struct color 8 | { 9 | static constexpr auto rule = dsl::hash_sign + dsl::times<3>(dsl::p) + dsl::eof; 10 | }; 11 | 12 | using production = color; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/color_function.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:rgb(255,0,255) 2 | struct channel_hex 3 | { 4 | static constexpr auto rule = dsl::integer(dsl::n_digits<2, dsl::hex>); 5 | }; 6 | 7 | struct channel_dec 8 | { 9 | static constexpr auto rule = dsl::integer; 10 | }; 11 | 12 | struct color 13 | { 14 | static constexpr auto rule = [] { 15 | auto hex_color = dsl::hash_sign >> dsl::times<3>(dsl::p); 16 | 17 | auto dec_channels = dsl::times<3>(dsl::p, dsl::sep(dsl::comma)); 18 | auto fnc_color = LEXY_LIT("rgb") >> dsl::parenthesized(dec_channels); 19 | 20 | return hex_color | fnc_color; 21 | }(); 22 | }; 23 | 24 | using production = color; 25 | -------------------------------------------------------------------------------- /docs/assets/playground/combination.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:cab 2 | struct production 3 | { 4 | static constexpr auto rule 5 | = dsl::combination(dsl::lit_c<'a'>, dsl::lit_c<'b'>, dsl::lit_c<'c'>); 6 | }; 7 | -------------------------------------------------------------------------------- /docs/assets/playground/context_counter.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:aaabb 2 | struct production 3 | { 4 | struct mismatch 5 | {}; 6 | 7 | static constexpr auto rule = [] { 8 | // Declare a counter - it is not created yet! 9 | auto counter = dsl::context_counter; 10 | 11 | // Parse a sequence of 'a' and add the number to it. 12 | auto a = counter.push(dsl::while_(dsl::lit_c<'a'>)); 13 | // Parse a sequence of 'b' and subtract the number from it. 14 | auto b = counter.pop(dsl::while_(dsl::lit_c<'b'>)); 15 | 16 | // Create the counter initialized to zero, 17 | // parse the two, and require its back to zero. 18 | return counter.create() + a + b + dsl::must(counter.is_zero()).error; 19 | }(); 20 | }; 21 | -------------------------------------------------------------------------------- /docs/assets/playground/context_flag.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:cccbab 2 | struct production 3 | { 4 | struct expected_a_before_b 5 | { 6 | static constexpr auto name = "expected a before b"; 7 | }; 8 | 9 | static constexpr auto rule = [] { 10 | // Declare a flag - it is not created yet! 11 | auto flag = dsl::context_flag; 12 | 13 | // Parsing a sets the flag to true. 14 | auto a = dsl::lit_c<'a'> >> flag.set(); 15 | // Parsing b requires that the flag has been set already. 16 | auto b = dsl::lit_c<'b'> >> dsl::must(flag.is_reset()).error; 17 | // Parsing c doesn't care about the flag. 18 | auto c = dsl::lit_c<'c'>; 19 | 20 | // Create the flag initialized to false. 21 | // Then parse a|b|c in a loop. 22 | return flag.create() + dsl::loop(a | b | c | dsl::break_); 23 | }(); 24 | }; 25 | -------------------------------------------------------------------------------- /docs/assets/playground/context_identifier.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello,Hallo 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Declare an identifier variable - it is not created yet! 6 | auto word = dsl::identifier(dsl::ascii::alpha); 7 | auto word_var = dsl::context_identifier(word); 8 | 9 | // Parse a word and capture it in the variable. 10 | auto first_word = word_var.capture(); 11 | // Parse another word and compare it agains the variable. 12 | auto second_word = word_var.rematch(); 13 | 14 | // Create the empty variable, then parse the two words. 15 | return word_var.create() + first_word + dsl::lit_c<','> + second_word; 16 | }(); 17 | }; 18 | -------------------------------------------------------------------------------- /docs/assets/playground/cpp_comment.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:// This is a comment. 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("//") + dsl::until(dsl::newline).or_eof(); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/default.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello World! 2 | struct name 3 | { 4 | static constexpr auto rule 5 | // One or more alpha numeric characters, underscores or hyphens. 6 | = dsl::identifier(dsl::unicode::alnum / dsl::lit_c<'_'> / dsl::lit_c<'-'>); 7 | }; 8 | 9 | struct production 10 | { 11 | // Allow arbitrary spaces between individual tokens. 12 | static constexpr auto whitespace = dsl::ascii::space; 13 | 14 | static constexpr auto rule = [] { 15 | auto greeting = LEXY_LIT("Hello"); 16 | return greeting + dsl::p + dsl::exclamation_mark + dsl::eof; 17 | }(); 18 | }; 19 | -------------------------------------------------------------------------------- /docs/assets/playground/digit.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:A 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::digit + dsl::eof; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/digits.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:4'294'967'295 2 | struct production 3 | { 4 | static constexpr auto rule 5 | = dsl::digits<>.sep(dsl::digit_sep_tick).no_leading_zero() + dsl::eof; 6 | }; 7 | -------------------------------------------------------------------------------- /docs/assets/playground/do_while.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello World 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto word = dsl::while_one(dsl::ascii::alpha); 6 | return dsl::do_while(word, dsl::ascii::space); 7 | }(); 8 | }; 9 | -------------------------------------------------------------------------------- /docs/assets/playground/eof.cpp: -------------------------------------------------------------------------------- 1 | struct production 2 | { 3 | static constexpr auto rule = dsl::eof; 4 | }; 5 | 6 | -------------------------------------------------------------------------------- /docs/assets/playground/eol.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("Hello") + dsl::eol; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /docs/assets/playground/equal_counts.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:aaabbcccc 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Parse 'a's and count them. 6 | auto ac = dsl::context_counter; 7 | auto a = ac.create() + ac.push(dsl::while_(dsl::lit_c<'a'>)); 8 | 9 | // Parse 'b's and count them. 10 | auto bc = dsl::context_counter; 11 | auto b = bc.create() + bc.push(dsl::while_(dsl::lit_c<'b'>)); 12 | 13 | // Parse 'c's and count them. 14 | auto cc = dsl::context_counter; 15 | auto c = cc.create() + cc.push(dsl::while_(dsl::lit_c<'c'>)); 16 | 17 | // Check that they're equal. 18 | auto check = dsl::equal_counts(ac, bc, cc); 19 | 20 | return a + b + c + check; 21 | }(); 22 | }; 23 | -------------------------------------------------------------------------------- /docs/assets/playground/exhausted_choice.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hey 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("Hello") | LEXY_LIT("Hi"); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/expected_char_class.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:8 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::digit; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/expected_literal.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello Warld! 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("Hello World!"); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/expr.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:3*2+-1 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct prefix : dsl::prefix_op 8 | { 9 | static constexpr auto op = dsl::op(dsl::lit_c<'-'>); 10 | using operand = dsl::atom; 11 | }; 12 | 13 | struct product : dsl::infix_op_left 14 | { 15 | static constexpr auto op = dsl::op(dsl::lit_c<'*'>) / dsl::op(dsl::lit_c<'/'>); 16 | using operand = prefix; 17 | }; 18 | 19 | struct sum : dsl::infix_op_left 20 | { 21 | static constexpr auto op = dsl::op(dsl::lit_c<'+'>) / dsl::op(dsl::lit_c<'-'>); 22 | using operand = product; 23 | }; 24 | 25 | using operation = sum; 26 | }; 27 | -------------------------------------------------------------------------------- /docs/assets/playground/expr_groups.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:1+2|3 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct math : dsl::infix_op_left 8 | { 9 | static constexpr auto op = dsl::op(dsl::lit_c<'+'>) / dsl::op(dsl::lit_c<'-'>); 10 | using operand = dsl::atom; 11 | }; 12 | 13 | struct bits : dsl::infix_op_left 14 | { 15 | static constexpr auto op = dsl::op(dsl::lit_c<'|'>) / dsl::op(dsl::lit_c<'&'>); 16 | using operand = dsl::atom; 17 | }; 18 | 19 | // Either a math or a bit operator, but not mixing. 20 | using operation = dsl::groups; 21 | }; 22 | -------------------------------------------------------------------------------- /docs/assets/playground/find.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:type Id = ;\nfunction foo(...) {\n ...\n}\n 2 | constexpr auto id = dsl::identifier(dsl::ascii::alpha); 3 | constexpr auto kw_function = LEXY_KEYWORD("function", id); 4 | constexpr auto kw_type = LEXY_KEYWORD("type", id); 5 | 6 | struct function_decl 7 | { 8 | static constexpr auto rule = [] { 9 | auto arguments = dsl::parenthesized(LEXY_LIT("...")); 10 | auto body = dsl::curly_bracketed(LEXY_LIT("...")); 11 | 12 | return kw_function >> id + arguments + body; 13 | }(); 14 | }; 15 | 16 | struct type_decl 17 | { 18 | static constexpr auto rule // 19 | = kw_type >> id + dsl::lit_c<'='> + id + dsl::semicolon; 20 | }; 21 | 22 | struct production 23 | { 24 | static constexpr auto whitespace = dsl::ascii::space; 25 | static constexpr auto rule = [] { 26 | auto decl = dsl::p | dsl::p; 27 | 28 | // We recover from any errors by skipping until the next decl. 29 | auto decl_recover = dsl::find(kw_function, kw_type); 30 | auto try_decl = dsl::try_(decl, decl_recover); 31 | 32 | return dsl::list(try_decl); 33 | }(); 34 | }; 35 | -------------------------------------------------------------------------------- /docs/assets/playground/identifier-unicode.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:ïdéntiför_123 2 | struct production 3 | { 4 | static constexpr auto rule 5 | = dsl::identifier(dsl::unicode::xid_start_underscore, // want '_' as well 6 | dsl::unicode::xid_continue); 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/identifier.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:identifier_123 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto head = dsl::ascii::alpha_underscore; 6 | auto tail = dsl::ascii::alpha_digit_underscore; 7 | return dsl::identifier(head, tail); 8 | }(); 9 | }; 10 | -------------------------------------------------------------------------------- /docs/assets/playground/if.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:3.14 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto integer = dsl::digits<>.no_leading_zero(); 6 | auto fraction = dsl::digits<>; 7 | 8 | return integer + dsl::if_(dsl::period >> fraction); 9 | }(); 10 | }; 11 | -------------------------------------------------------------------------------- /docs/assets/playground/infix_op_left.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:1+2+3 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct operation : dsl::infix_op_left 8 | { 9 | static constexpr auto op = dsl::op(dsl::lit_c<'+'>); 10 | using operand = dsl::atom; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/infix_op_list.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:1+2+3 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct operation : dsl::infix_op_list 8 | { 9 | static constexpr auto op = dsl::op(dsl::lit_c<'+'>); 10 | using operand = dsl::atom; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/infix_op_right.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:1**2**3 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct operation : dsl::infix_op_right 8 | { 9 | static constexpr auto op = dsl::op(LEXY_LIT("**")); 10 | using operand = dsl::atom; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/infix_op_single.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:1<2<3 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct operation : dsl::infix_op_single 8 | { 9 | static constexpr auto op = dsl::op(dsl::lit_c<'<'>); 10 | using operand = dsl::atom; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/inline.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello World! 2 | struct name 3 | { 4 | static constexpr auto rule 5 | // One or more alpha numeric characters, underscores or hyphens. 6 | = dsl::identifier(dsl::unicode::alnum / dsl::lit_c<'_'> / dsl::lit_c<'-'>); 7 | }; 8 | 9 | struct production 10 | { 11 | // Allow arbitrary spaces between individual tokens. 12 | // Note that this includes the individual characters of the name. 13 | static constexpr auto whitespace = dsl::ascii::space; 14 | 15 | static constexpr auto rule = [] { 16 | auto greeting = LEXY_LIT("Hello"); 17 | return greeting + dsl::inline_ + dsl::exclamation_mark + dsl::eof; 18 | }(); 19 | }; 20 | -------------------------------------------------------------------------------- /docs/assets/playground/keyword.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:integer 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Define the general identifier syntax. 6 | auto head = dsl::ascii::alpha_underscore; 7 | auto tail = dsl::ascii::alpha_digit_underscore; 8 | auto id = dsl::identifier(head, tail); 9 | 10 | // Parse a keyword. 11 | return LEXY_KEYWORD("int", id); 12 | }(); 13 | }; 14 | -------------------------------------------------------------------------------- /docs/assets/playground/lit.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello World! 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("Hello World!"); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/lit_ascii.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello World! 2 | struct production 3 | { 4 | // The character type doesn't matter if it only contains ASCII characters. 5 | // The literal is encoded in UTF-16 whereas the (playground) input 6 | // is encoded in UTF-8, but as its only ASCII characters, 7 | // lexy will transcode for you. 8 | static constexpr auto rule = LEXY_LIT(u"Hello World!"); 9 | }; 10 | -------------------------------------------------------------------------------- /docs/assets/playground/lit_cp.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:🙂 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::lit_cp<0x1F642> + dsl::eof; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/lit_utf8.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:ä 2 | struct production 3 | { 4 | // The string literal contains UTF-8 text, 5 | // which means the input needs to be UTF-8 encoded as well. 6 | // 7 | // WARNING: This will only match if both agree on a normalization for 'ä'! 8 | static constexpr auto rule = LEXY_LIT(u8"ä"); 9 | }; 10 | -------------------------------------------------------------------------------- /docs/assets/playground/literal_set.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:abc 2 | struct production 3 | { 4 | static constexpr auto rule // 5 | = dsl::literal_set(LEXY_LIT("a"), LEXY_LIT("abc"), LEXY_LIT("bc")); 6 | }; 7 | -------------------------------------------------------------------------------- /docs/assets/playground/loop.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:type Id = Int;\nfunction foo(...) {\n ...\n}\n 2 | constexpr auto id = dsl::identifier(dsl::ascii::alpha); 3 | constexpr auto kw_function = LEXY_KEYWORD("function", id); 4 | constexpr auto kw_type = LEXY_KEYWORD("type", id); 5 | 6 | struct function_decl 7 | { 8 | static constexpr auto rule = [] { 9 | auto arguments = dsl::parenthesized(LEXY_LIT("...")); 10 | auto body = dsl::curly_bracketed(LEXY_LIT("...")); 11 | 12 | return kw_function >> id + arguments + body; 13 | }(); 14 | }; 15 | 16 | struct type_decl 17 | { 18 | static constexpr auto rule // 19 | = kw_type >> id + dsl::lit_c<'='> + id + dsl::semicolon; 20 | }; 21 | 22 | struct production 23 | { 24 | static constexpr auto whitespace = dsl::ascii::space; 25 | static constexpr auto rule 26 | // Note: a real implementation couldn't use loop(). 27 | // If the decls produce values, list() has to be used instead. 28 | = dsl::loop(dsl::p | dsl::p | dsl::break_); 29 | }; 30 | -------------------------------------------------------------------------------- /docs/assets/playground/manual_whitespace.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello\nWorld !\n 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto ws = dsl::whitespace(dsl::ascii::space); 6 | return LEXY_LIT("Hello") + ws + LEXY_LIT("World") // 7 | + ws + dsl::exclamation_mark + ws + dsl::eof; 8 | }(); 9 | }; 10 | -------------------------------------------------------------------------------- /docs/assets/playground/minus_sign.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:-123 2 | struct production 3 | { 4 | static constexpr auto rule 5 | // Minus sign followed by a decimal integer. 6 | = dsl::minus_sign + dsl::integer; 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/must.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:echo World 2 | struct production 3 | { 4 | struct expected_sep 5 | { 6 | static constexpr auto name = "expected separator"; 7 | }; 8 | 9 | static constexpr auto rule = [] { 10 | // A separator is either blank or \ + newline. 11 | // If a separator is not present, raise the specific error. 12 | auto blank = dsl::ascii::blank; 13 | auto escaped_nl = dsl::backslash >> dsl::newline; 14 | auto sep = dsl::must(blank | escaped_nl).error; 15 | 16 | return LEXY_LIT("echo") + sep 17 | + dsl::identifier(dsl::ascii::alnum) 18 | // Allow an optional separator before EOL. 19 | + dsl::if_(sep) + dsl::eol; 20 | }(); 21 | }; 22 | -------------------------------------------------------------------------------- /docs/assets/playground/n_digits.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:\xABCDEF 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("\\x") + dsl::n_digits<2, dsl::hex>; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/newline.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello\n 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("Hello") + dsl::newline; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /docs/assets/playground/no_trailing.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello World! 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_LIT("Hello") + dsl::eof; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /docs/assets/playground/no_whitespace.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello\nWorld ! 2 | struct production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto rule // 6 | = dsl::no_whitespace(LEXY_LIT("Hello") + LEXY_LIT("World")) // 7 | + dsl::exclamation_mark + dsl::eof; 8 | }; 9 | -------------------------------------------------------------------------------- /docs/assets/playground/not_followed_by.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:== 2 | struct production 3 | { 4 | static constexpr auto rule 5 | // = but then not another = 6 | = dsl::not_followed_by(dsl::lit_c<'='>, dsl::lit_c<'='>); 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/one_of.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:B 2 | struct production 3 | { 4 | static constexpr auto rule = LEXY_ASCII_ONE_OF("CDEFGB"); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/parenthesized.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:(abc,12,abc123,123) 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto item = LEXY_LIT("abc") | LEXY_LIT("123"); 6 | 7 | return dsl::parenthesized.list(item, dsl::sep(dsl::comma)); 8 | }(); 9 | }; 10 | -------------------------------------------------------------------------------- /docs/assets/playground/partial_combination.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:ca 2 | struct production 3 | { 4 | static constexpr auto rule 5 | = dsl::partial_combination(dsl::lit_c<'a'>, dsl::lit_c<'b'>, dsl::lit_c<'c'>); 6 | }; 7 | -------------------------------------------------------------------------------- /docs/assets/playground/peek.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:-11 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Number with optional minus sign. 6 | auto number = dsl::minus_sign + dsl::digits<>; 7 | 8 | // Only parse a number if we have a minus or digit. 9 | auto condition = dsl::peek(dsl::lit_c<'-'> / dsl::digit<>); 10 | return dsl::if_(condition >> number); 11 | }(); 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/peek_not.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello World \n 2 | struct production 3 | { 4 | struct trailing_spaces 5 | { 6 | static constexpr auto name = "trailing spaces"; 7 | }; 8 | 9 | static constexpr auto rule 10 | = LEXY_LIT("Hello World") 11 | + dsl::peek_not(dsl::while_one(dsl::ascii::space)).error + dsl::eof; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/plus_sign.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:+123 2 | struct production 3 | { 4 | static constexpr auto rule 5 | // Plus sign followed by a decimal integer. 6 | = dsl::plus_sign + dsl::integer; 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/position.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:function foo(...)\n{\n ...\n} 2 | struct production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | 6 | static constexpr auto rule = [] { 7 | auto id = dsl::identifier(dsl::ascii::alpha); 8 | auto kw_function = LEXY_KEYWORD("function", id); 9 | 10 | auto arguments = dsl::parenthesized(LEXY_LIT("...")); 11 | auto body = dsl::curly_bracketed(LEXY_LIT("...")); 12 | 13 | // The position of a function is the first character of the name. 14 | return kw_function + dsl::position + id + arguments + body; 15 | }(); 16 | }; 17 | -------------------------------------------------------------------------------- /docs/assets/playground/postfix_op.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:1++++ 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct operation : dsl::postfix_op 8 | { 9 | static constexpr auto op = dsl::op(LEXY_LIT("++")); 10 | using operand = dsl::atom; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/prefix_op.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:--1 2 | struct production : lexy::expression_production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto atom = dsl::integer; 6 | 7 | struct operation : dsl::prefix_op 8 | { 9 | static constexpr auto op = dsl::op(dsl::lit_c<'-'>); 10 | using operand = dsl::atom; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/quoted.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:"Hello World!" 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Arbitrary code points that aren't control characters. 6 | auto c = -dsl::ascii::control; 7 | 8 | return dsl::quoted(c); 9 | }(); 10 | }; 11 | -------------------------------------------------------------------------------- /docs/assets/playground/quoted_error.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:"Hello\nWorld" 2 | struct production 3 | { 4 | struct invalid_character 5 | { 6 | static constexpr auto name = "invalid character"; 7 | }; 8 | 9 | static constexpr auto rule = [] { 10 | // Arbitrary code points that aren't control characters. 11 | auto c = (-dsl::ascii::control).error; 12 | 13 | return dsl::quoted(c); 14 | }(); 15 | }; 16 | -------------------------------------------------------------------------------- /docs/assets/playground/quoted_limit.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:"Hello World!\n 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Arbitrary code points that aren't control characters. 6 | auto c = -dsl::ascii::control; 7 | 8 | // If we have a newline inside our string, we're missing the closing ". 9 | auto quoted = dsl::quoted.limit(dsl::ascii::newline); 10 | return quoted(c); 11 | }(); 12 | }; 13 | -------------------------------------------------------------------------------- /docs/assets/playground/quoted_token.cpp: -------------------------------------------------------------------------------- 1 | // INPUT: " Hello World! " ; 2 | struct quoted : lexy::token_production 3 | { 4 | static constexpr auto rule = [] { 5 | // Arbitrary code points that aren't control characters. 6 | auto c = -dsl::ascii::control; 7 | 8 | return dsl::quoted(c); 9 | }(); 10 | }; 11 | 12 | struct production 13 | { 14 | static constexpr auto whitespace = dsl::ascii::space; 15 | static constexpr auto rule = dsl::p + dsl::semicolon; 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /docs/assets/playground/recover.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:type Id = ;\nfunction foo(...) {\n ...\n}\n 2 | constexpr auto id = dsl::identifier(dsl::ascii::alpha); 3 | constexpr auto kw_function = LEXY_KEYWORD("function", id); 4 | constexpr auto kw_type = LEXY_KEYWORD("type", id); 5 | 6 | struct function_decl 7 | { 8 | static constexpr auto rule = [] { 9 | auto arguments = dsl::parenthesized(LEXY_LIT("...")); 10 | auto body = dsl::curly_bracketed(LEXY_LIT("...")); 11 | 12 | return kw_function >> id + arguments + body; 13 | }(); 14 | }; 15 | 16 | struct type_decl 17 | { 18 | static constexpr auto rule // 19 | = kw_type >> id + dsl::lit_c<'='> + id + dsl::semicolon; 20 | }; 21 | 22 | struct production 23 | { 24 | static constexpr auto whitespace = dsl::ascii::space; 25 | static constexpr auto rule = [] { 26 | auto decl = dsl::p | dsl::p; 27 | 28 | // We recover from any errors by continuing with the next declaration. 29 | auto decl_recover = dsl::recover(dsl::p, dsl::p); 30 | auto try_decl = dsl::try_(decl, decl_recover); 31 | 32 | return dsl::list(try_decl); 33 | }(); 34 | }; 35 | -------------------------------------------------------------------------------- /docs/assets/playground/recurse.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:(((atom))) 2 | struct production 3 | { 4 | static constexpr auto rule 5 | // Either we parse ourselves surrounded by expressions, or an atom. 6 | = dsl::parenthesized(dsl::recurse) | LEXY_LIT("atom"); 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/recurse_limit.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:((((atom)))) 2 | struct production 3 | { 4 | // We define a (tiny) maximum recursion depth. 5 | // This prevents unbounded recursion which can cause a stack overflow. 6 | static constexpr auto max_recursion_depth = 3; 7 | 8 | static constexpr auto rule 9 | // Either we parse ourselves surrounded by expressions, or an atom. 10 | = dsl::parenthesized(dsl::recurse) | LEXY_LIT("atom"); 11 | }; 12 | -------------------------------------------------------------------------------- /docs/assets/playground/repeat.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:3aaa 2 | struct production 3 | { 4 | static constexpr auto rule 5 | // The number of 'a's is determined by the integer value. 6 | = dsl::repeat(dsl::integer)(dsl::lit_c<'a'>); 7 | }; 8 | -------------------------------------------------------------------------------- /docs/assets/playground/reserved_identifier.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:reserved__id 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Define the general identifier syntax. 6 | auto head = dsl::ascii::alpha_underscore; 7 | auto tail = dsl::ascii::alpha_digit_underscore; 8 | auto id = dsl::identifier(head, tail); 9 | 10 | // Define some keywords. 11 | auto kw_int = LEXY_KEYWORD("int", id); 12 | auto kw_struct = LEXY_KEYWORD("struct", id); 13 | // ... 14 | 15 | // Parse an identifier 16 | return id 17 | // ... that is not a keyword, 18 | .reserve(kw_int, kw_struct) 19 | // ... doesn't start with an underscore, 20 | .reserve_prefix(dsl::lit_c<'_'>) 21 | // ... or contains a double underscore. 22 | .reserve_containing(LEXY_LIT("__")); 23 | }(); 24 | }; 25 | -------------------------------------------------------------------------------- /docs/assets/playground/reserved_identifier_case_folding.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:sTrUcT 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | // Define the general identifier syntax. 6 | auto head = dsl::ascii::alpha_underscore; 7 | auto tail = dsl::ascii::alpha_digit_underscore; 8 | auto id = dsl::identifier(head, tail); 9 | 10 | // Define some case insensitive keywords. 11 | auto kw_int = dsl::ascii::case_folding(LEXY_KEYWORD("int", id)); 12 | auto kw_struct = dsl::ascii::case_folding(LEXY_KEYWORD("struct", id)); 13 | // ... 14 | 15 | // Parse an identifier that is not a keyword. 16 | return id.reserve(kw_int, kw_struct); 17 | }(); 18 | }; 19 | -------------------------------------------------------------------------------- /docs/assets/playground/return.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:
2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto tag_name = dsl::identifier(dsl::ascii::alpha); 6 | 7 | // If we're having tag name followed by a `/`, 8 | // it is an empty element without content. 9 | // Immediately return in that case. 10 | auto if_empty = dsl::if_(dsl::lit_c<'/'> >> dsl::return_); 11 | auto open_tag = dsl::angle_bracketed(tag_name + if_empty); 12 | auto close_tag = dsl::angle_bracketed(dsl::lit_c<'/'> + tag_name); 13 | 14 | // Placeholder content. 15 | auto content = LEXY_LIT("content"); 16 | 17 | return open_tag + content + close_tag; 18 | }(); 19 | }; 20 | -------------------------------------------------------------------------------- /docs/assets/playground/scan-recovery.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:"123abc" 2 | struct production : lexy::scan_production 3 | { 4 | template 5 | static constexpr scan_result scan(lexy::rule_scanner& scanner) 6 | { 7 | // Parse the initial quote. 8 | scanner.parse(dsl::lit_c<'"'>); 9 | if (!scanner) 10 | return lexy::scan_failed; 11 | 12 | // Parse an integer. 13 | lexy::scan_result integer; 14 | scanner.parse(integer, dsl::integer); 15 | if (!scanner) 16 | return lexy::scan_failed; 17 | 18 | // Parse the closing quote. 19 | scanner.parse(dsl::lit_c<'"'>); 20 | if (!scanner) 21 | { 22 | // Recover by discarding everything until a closing quote is found. 23 | auto recovery = scanner.error_recovery(); 24 | while (!scanner.branch(dsl::lit_c<'"'>)) 25 | { 26 | if (!scanner.discard(dsl::ascii::character)) 27 | { 28 | // We've failed to recover. 29 | LEXY_MOV(recovery).cancel(); 30 | return lexy::scan_failed; 31 | } 32 | } 33 | LEXY_MOV(recovery).finish(); 34 | } 35 | 36 | return integer.value(); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /docs/assets/playground/terminator.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:statement; 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto terminator = dsl::terminator(dsl::semicolon); 6 | return terminator(LEXY_LIT("statement")); 7 | }(); 8 | }; 9 | -------------------------------------------------------------------------------- /docs/assets/playground/terminator_list.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:abc,12,abc123,123. 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto item = LEXY_LIT("abc") | LEXY_LIT("123"); 6 | 7 | auto terminator = dsl::terminator(dsl::period); 8 | return terminator.list(item, dsl::sep(dsl::comma)); 9 | }(); 10 | }; 11 | -------------------------------------------------------------------------------- /docs/assets/playground/terminator_opt.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:; 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto terminator = dsl::terminator(dsl::semicolon); 6 | return terminator.opt(LEXY_LIT("statement")); 7 | }(); 8 | }; 9 | -------------------------------------------------------------------------------- /docs/assets/playground/terminator_recovery.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:{\n foo();\n error1;\n bar();\n error2\n foo();\n error3\n} 2 | struct statement 3 | { 4 | static constexpr auto rule = [] { 5 | // A statement is terminated by a semicolon. 6 | // Error recovery fails when we've reached the } of the scope. 7 | auto terminator = dsl::terminator(dsl::semicolon).limit(dsl::lit_c<'}'>); 8 | return terminator.opt(LEXY_LIT("foo()") | LEXY_LIT("bar()")); 9 | }(); 10 | }; 11 | 12 | struct production 13 | { 14 | static constexpr auto whitespace = dsl::ascii::space; 15 | 16 | // Just a list of statements surrounded by {}. 17 | static constexpr auto rule = dsl::curly_bracketed.list(dsl::p); 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /docs/assets/playground/terminator_try.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:state; 2 | struct production 3 | { 4 | static constexpr auto rule = [] { 5 | auto terminator = dsl::terminator(dsl::semicolon); 6 | return terminator.try_(LEXY_LIT("statement")); 7 | }(); 8 | }; 9 | -------------------------------------------------------------------------------- /docs/assets/playground/trace.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello abx! 2 | struct name 3 | { 4 | static constexpr auto rule = dsl::identifier(dsl::ascii::alpha); 5 | }; 6 | 7 | struct alphabet 8 | { 9 | static constexpr auto rule 10 | // Just something stupid, so we can see a backtrack. 11 | = dsl::peek(LEXY_LIT("abc")) >> LEXY_LIT("abcdefg"); 12 | }; 13 | 14 | struct number 15 | { 16 | static constexpr auto rule = dsl::identifier(dsl::ascii::digit); 17 | }; 18 | 19 | struct object 20 | { 21 | struct unexpected 22 | { 23 | static constexpr auto name = "unexpected"; 24 | }; 25 | 26 | static constexpr auto rule 27 | = dsl::p | dsl::p | dsl::p 28 | // Issue an error, but recover. 29 | | dsl::try_(dsl::error); 30 | }; 31 | 32 | struct production 33 | { 34 | static constexpr auto whitespace = dsl::ascii::space; 35 | 36 | static constexpr auto rule = [] { 37 | auto greeting = LEXY_LIT("Hello"); 38 | return greeting + LEXY_DEBUG("finished greeting") // 39 | + dsl::p + dsl::exclamation_mark; 40 | }(); 41 | }; 42 | -------------------------------------------------------------------------------- /docs/assets/playground/while.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::while_(dsl::ascii::alpha); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/while_bad.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:aaa 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::while_(dsl::lit_c<'a'>) + dsl::lit_c<'a'>; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/while_one.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::while_one(dsl::ascii::alpha); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/assets/playground/whitespace.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello\nWorld ! 2 | struct production 3 | { 4 | static constexpr auto whitespace = dsl::ascii::space; 5 | static constexpr auto rule // 6 | = LEXY_LIT("Hello") + LEXY_LIT("World") // 7 | + dsl::exclamation_mark + dsl::eof; 8 | }; 9 | -------------------------------------------------------------------------------- /docs/assets/playground/whitespace_comment.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:Hello /* C comment */\nWorld ! 2 | struct production 3 | { 4 | // Note that an unterminated C comment will raise an error. 5 | static constexpr auto whitespace 6 | = dsl::ascii::space | LEXY_LIT("/*") >> dsl::until(LEXY_LIT("*/")); 7 | 8 | static constexpr auto rule // 9 | = LEXY_LIT("Hello") + LEXY_LIT("World") + dsl::exclamation_mark; 10 | }; 11 | -------------------------------------------------------------------------------- /docs/assets/playground/zero.cpp: -------------------------------------------------------------------------------- 1 | // INPUT:0 2 | struct production 3 | { 4 | static constexpr auto rule = dsl::zero + dsl::eof; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/config.toml: -------------------------------------------------------------------------------- 1 | title = "lexy" 2 | baseURL = "https://lexy.foonathan.net/" 3 | languageCode = "en-us" 4 | copyright = "2020-2025 Jonathan Müller and lexy contributors" 5 | 6 | disableKinds = ["RSS", "taxonomy"] 7 | 8 | [markup.tableOfContents] 9 | startLevel = 2 10 | endLevel = 3 11 | 12 | [markup.asciidocExt.attributes] 13 | source-highlighter = 'rouge' 14 | 15 | [security.exec] 16 | allow = ['^asciidoctor$'] 17 | 18 | [params] 19 | tagline = "C++ parsing DSL" 20 | github = "https://github.com/foonathan/lexy" 21 | github_src_prefix = "https://github.com/foonathan/lexy/blob/main" 22 | github_edit_prefix = "https://github.com/foonathan/lexy/edit/main" 23 | 24 | -------------------------------------------------------------------------------- /docs/content/download/_index.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Download 3 | layout: single 4 | menu: 5 | main: 6 | name: "Download" 7 | weight: 4 8 | --- 9 | 10 | For build instructions, read link:{{< relref "learn/build" >}}[the tutorial]. 11 | 12 | {{% release_list %}} 13 | 14 | -------------------------------------------------------------------------------- /docs/content/learn/_index.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | layout: single 3 | title: Learn 4 | menu: 5 | main: 6 | name: "Learn" 7 | weight: 1 8 | --- 9 | 10 | New to lexy? Start here. 11 | 12 | ## Getting started 13 | 14 | 1. link:{{< relref "learn/build" >}}[Building lexy and integrating it in your own projects] 15 | 2. link:{{< relref "learn/warmup" >}}[Warming up -- the first parser] 16 | 3. link:{{< relref "learn/branching" >}}[Branching, backtracking and making decisions -- lexy is not declarative] 17 | 4. link:{{< relref "learn/walkthrough" >}}[Walkthrough -- parser for custom package format] 18 | 19 | ## Development 20 | 21 | * link:{{< relref "learn/changelog" >}}[Changelog] 22 | * link:{{< relref "learn/versioning" >}}[Versioning and compatibility policy] 23 | 24 | ## Need more help? 25 | 26 | Please look at https://github.com/foonathan/lexy/discussions/categories/q-a[previous questions] or https://github.com/foonathan/lexy/discussions/new[ask a new one]. 27 | 28 | -------------------------------------------------------------------------------- /docs/content/playground/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Playground" 3 | menu: 4 | main: 5 | name: "Playground" 6 | weight: 3 7 | --- 8 | 9 | Enter the grammar in the left editor (`lexy/dsl.hpp` and namespace alias `dsl` is pre-included) and the input in the right editor. 10 | The result of parsing the selected entry production on that input is displayed in the bottom window. 11 | The encoding is `lexy::utf8_encoding`. 12 | 13 | The online playground is powered by [Compiler Explorer](https://godbolt.org/), [Ace](https://ace.c9.io/), [ansi_up](https://github.com/drudru/ansi_up), and [d3-graphviz](https://github.com/magjac/d3-graphviz). 14 | 15 | -------------------------------------------------------------------------------- /docs/content/reference/action/match.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/action/match.hpp" 3 | entities: 4 | "lexy::match": match 5 | --- 6 | :toc: left 7 | 8 | [#match] 9 | == Action `lexy::match` 10 | 11 | {{% interface %}} 12 | ---- 13 | namespace lexy 14 | { 15 | template 16 | struct match_action; 17 | 18 | template <_production_ Production> 19 | constexpr bool match(const _input_ auto& input); 20 | 21 | template <_production_ Production, typename ParseState> 22 | constexpr bool match(const _input_ auto& input, ParseState& state); 23 | template <_production_ Production, typename ParseState> 24 | constexpr bool match(const _input_ auto& input, const ParseState& state); 25 | } 26 | ---- 27 | 28 | [.lead] 29 | An action that determines whether `Production` matches on `input`. 30 | 31 | It parses `Production` on input. 32 | All values produced during parsing are discarded; 33 | all errors ignored. 34 | Returns `true` if parsing was successful without errors, 35 | returns `false` if parsing lead to an error, even if it recovered. 36 | 37 | TIP: Use {{% docref "lexy::validate" %}} to get information about the parse error. 38 | 39 | NOTE: `Production` does not need to match the entire `input` to succeed. 40 | Use {{% docref "lexy::dsl::eof" %}} if it should fail when it didn't consume the entire input. 41 | 42 | -------------------------------------------------------------------------------- /docs/content/reference/callback/bit_cast.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/callback/bit_cast.hpp" 3 | entities: 4 | "lexy::bit_cast": bit_cast 5 | --- 6 | 7 | [#bit_cast] 8 | == Callback `lexy::bit_cast` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy 13 | { 14 | template 15 | constexpr _callback_ auto bit_cast; 16 | } 17 | ---- 18 | 19 | [.lead] 20 | A callback that calls https://en.cppreference.com/w/cpp/numeric/bit_cast[`std::bit_cast`]. 21 | 22 | It requires that `T` is trivially copyable. 23 | It accepts any type that is also trivially copyable and has the same size as `T`. 24 | It then converts the argument to `T` by reinterpreting the bits. 25 | 26 | NOTE: If `std::bit_cast` is not available, it is emulated. 27 | This might make the callback non-`constexpr` and require that `T` is in addition default constructible. 28 | 29 | -------------------------------------------------------------------------------- /docs/content/reference/callback/constant.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/callback/constant.hpp" 3 | entities: 4 | "lexy::constant": constant 5 | --- 6 | :toc: left 7 | 8 | [#constant] 9 | == Callback `lexy::constants` 10 | 11 | {{% interface %}} 12 | ---- 13 | namespace lexy 14 | { 15 | template 16 | consteval _callback_ auto constant(Arg&& arg); 17 | } 18 | ---- 19 | 20 | [.lead] 21 | Produces a constant value. 22 | 23 | It is a callback that accepts zero arguments and produces a copy of the constant. 24 | 25 | {{% godbolt-example "true_false" "Produce constant values" %}} 26 | 27 | -------------------------------------------------------------------------------- /docs/content/reference/callback/forward.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/callback/forward.hpp" 3 | entities: 4 | "lexy::forward": forward 5 | --- 6 | 7 | [#forward] 8 | == Callback `lexy::forward` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy 13 | { 14 | template 15 | constexpr _callback_ auto forward; 16 | 17 | template <> 18 | constexpr _callback_ auto forward; 19 | } 20 | ---- 21 | 22 | [.lead] 23 | `lexy::forward` is a callback that forwards an existing object. 24 | 25 | The primary template accepts `const T&` and `T&&` and forwards them as a `T`. 26 | 27 | The specialization for `void` is both a callback and a sink. 28 | As a callback it accepts no arguments or a single argument of type {{% docref "lexy::nullopt" %}}, and does nothing to return `void`. 29 | As a sink, it can be invoked multiple times with the same arguments, doing nothing and finally returning `void`. 30 | 31 | {{% godbolt-example "true_false" "Forward the value of child productions" %}} 32 | 33 | -------------------------------------------------------------------------------- /docs/content/reference/callback/integer.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/callback/integer.hpp" 3 | entities: 4 | "lexy::as_integer": as_integer 5 | --- 6 | 7 | [#as_integer] 8 | == Callback `lexy::as_integer` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy 13 | { 14 | template 15 | constexpr _callback_ auto as_integer; 16 | } 17 | ---- 18 | 19 | [.lead] 20 | Creates an integer of type `T`. 21 | 22 | It is a callback with three overloads: 23 | 24 | `(const auto& value)`:: returns `T(value)`. 25 | `(lexy::plus_sign, const auto& value)`:: returns `T(value)`. 26 | `(lexy::minus_sign, const auto& value)`:: returns `T(-value)`. 27 | 28 | It is best used together with {{% docref "lexy::dsl::integer" %}} and {{% docref "lexy::dsl::sign" %}}. 29 | 30 | {{% godbolt-example sign "A number with an optional plus/minus sign" %}} 31 | 32 | -------------------------------------------------------------------------------- /docs/content/reference/callback/noop.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/callback/noop.hpp" 3 | entities: 4 | "lexy::noop": noop 5 | --- 6 | 7 | [#noop] 8 | == Callback and sink `lexy::noop` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy 13 | { 14 | constexpr _callback_ auto noop; 15 | constexpr _sink<>_ auto noop; 16 | } 17 | ---- 18 | 19 | [.lead] 20 | A callback and sink that ignores all arguments and returns `void`. 21 | 22 | As a callback, it can be called with arbitrary arguments that are all ignored. 23 | As a sink, the sink callback also ignores all arguments. 24 | 25 | {{% godbolt-example "noop" "Ignore all errors produced during parsing" %}} 26 | 27 | -------------------------------------------------------------------------------- /docs/content/reference/callback/object.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/callback/object.hpp" 3 | entities: 4 | "lexy::construct": construct 5 | "lexy::new_": new_ 6 | --- 7 | :toc: left 8 | 9 | [.lead] 10 | Construct objects. 11 | 12 | [#construct] 13 | == Callback `lexy::construct` 14 | 15 | {{% interface %}} 16 | ---- 17 | namespace lexy 18 | { 19 | template 20 | constexpr _callback_ auto construct; 21 | 22 | template <> 23 | constexpr _callback_ auto construct; 24 | } 25 | ---- 26 | 27 | [.lead] 28 | Construct an object of type `T`. 29 | 30 | The primary template accepts arbitrary arguments and returns `T(std::forward(args)...)` if that is well-formed, 31 | otherwise `T{std::forward(args)...}`. 32 | The specialization for `void` accepts no arguments and does nothing to return `void`. 33 | 34 | {{% godbolt-example "point" "Construct a point from two integers" %}} 35 | 36 | NOTE: `construct` supports both types with constructor as well as aggregates or built-in types. 37 | 38 | [#new_] 39 | == Callback `lexy::new_` 40 | 41 | {{% interface %}} 42 | ---- 43 | namespace lexy 44 | { 45 | template 46 | constexpr _callback_ auto new_; 47 | } 48 | ---- 49 | 50 | [.lead] 51 | Construct an object of type `T` on the heap. 52 | 53 | It accepts arbitrary arguments and calls `new T(std::forward(args)...)` if that is well-formed, 54 | otherwise `new T{std::forward(args)...}`. 55 | Then returns a pointer of the specified type as the result. 56 | 57 | {{% godbolt-example "new" "Construct a point on the heap and returns a `std::unique_ptr`" %}} 58 | 59 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/any.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/any.hpp" 3 | entities: 4 | "lexy::dsl::any": any 5 | --- 6 | 7 | [#any] 8 | == Token rule `lexy::dsl::any` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy::dsl 13 | { 14 | constexpr _token-rule_ auto any; 15 | } 16 | ---- 17 | 18 | [.lead] 19 | `any` is a {{% token-rule %}} that matches anything. 20 | 21 | Matching:: 22 | Consumes the entire input. 23 | If the rule is matched in a context where the reader has been artificially delimited, 24 | consumes only until the end of the partial input is reached. 25 | Errors:: 26 | None. 27 | Parse tree:: 28 | Single token node with the {{% docref "lexy::predefined_token_kind" %}} `lexy::any_token_kind`. 29 | 30 | {{% playground-example any "Match literally any input" %}} 31 | 32 | CAUTION: `any` does not care what input it consumes; it can be anything, including ill-formed Unicode. 33 | To restrict the input that is consumed, use {{% docref "lexy::dsl::while_" %}} instead. 34 | 35 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/bom.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/bom.hpp" 3 | entities: 4 | "lexy::dsl::bom": bom 5 | --- 6 | 7 | [#bom] 8 | == Literal rule `lexy::dsl::bom` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy::dsl 13 | { 14 | template 15 | constexpr _literal-rule_ auto bom; 16 | } 17 | ---- 18 | 19 | [.lead] 20 | `bom` is a {{% literal-rule %}} that matches the https://en.wikipedia.org/wiki/Byte_order_mark[byte order mark (BOM)] of the given {{% encoding %}} in the given {{% docref "lexy::encoding_endianness" %}}. 21 | 22 | It is equivalent to the {{% docref "lexy::dsl::lit_b" %}} rule given in the table above. 23 | If the combination of `Encoding` and `Endianness` is not listed, it succeeds without matching anything. 24 | 25 | [%collapsible] 26 | .The possible BOMs 27 | ==== 28 | |=== 29 | | Encoding | Endianness | BOM 30 | 31 | | UTF-8 | _ignored_ | `lit_b<0xEF, 0xBB, 0xBF>` 32 | | UTF-16 | little | `lit_b<0xFF, 0xFE>` 33 | | UTF-16 | big | `lit_b<0xFE, 0xFF>` 34 | | UTF-32 | little | `lit_b<0xFF, 0xFE, 0x00, 0x00>` 35 | | UTF-32 | big | `lit_b<0x00, 0x00, 0xFE, 0xFF>` 36 | 37 | |=== 38 | ==== 39 | 40 | {{% godbolt-example bom "Skip an optional UTF-8 BOM" %}} 41 | 42 | CAUTION: As a token rule, it matches whitespace immediately following the BOM. 43 | As such, the rule is best used in contexts where automatic whitespace skipping is disabled. 44 | 45 | NOTE: When using `lexy::read_file()` as input, BOM has been taken care of by default. 46 | 47 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/capture.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/capture.hpp" 3 | entities: 4 | "lexy::dsl::capture": capture 5 | --- 6 | 7 | [#capture] 8 | == Branch rule `lexy::dsl::capture` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy::dsl 13 | { 14 | constexpr _branch-rule_ auto capture(_rule_ auto rule); 15 | } 16 | ---- 17 | 18 | [.lead] 19 | `capture` is a {{% branch-rule %}} that parses `rule` capturing everything it has consumed but excluding whitespace as a value. 20 | 21 | Requires:: 22 | `rule` is either a {{% token-rule %}} or {{% docref "lexy::dsl::p" %}} where the production is a token production. 23 | (Branch) Parsing:: 24 | Parses `rule` unchanged. 25 | Errors:: 26 | All errors raised by `rule`. 27 | The rule then fails if `rule` has failed. 28 | Values:: 29 | A {{% docref "lexy::lexeme" %}} whose range covers everything consumed by `token` except any trailing whitespace. 30 | Then all values produced by `rule`. 31 | 32 | {{% godbolt-example capture "Get a single code point" %}} 33 | 34 | TIP: Use the callback {{% docref "lexy::as_string" %}} to convert the {{% docref "lexy::lexeme" %}} to a string. 35 | 36 | TIP: In most cases, you should prefer {{% docref "lexy::dsl::identifier" %}} instead. 37 | 38 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/effect.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/effect.hpp" 3 | entities: 4 | "lexy::dsl::effect": effect 5 | --- 6 | 7 | [#effect] 8 | == Rule `lexy::dsl::effect` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy::dsl 13 | { 14 | template 15 | constexpr _rule_ auto effect; 16 | } 17 | ---- 18 | 19 | [.lead] 20 | `effect` is a {{% rule %}} that always succeeds but invokes `Fn` for its side-effect. 21 | 22 | Parsing:: 23 | Succeeds without consuming anything. 24 | Errors:: 25 | No errors. 26 | Values:: 27 | Invokes `Fn`, either with no arguments or the provided parse state. 28 | If it returns a non-void value, produces it. 29 | Otherwise, produces nothing. 30 | 31 | NOTE: Since this is not a branch rule, it will never backtrack. 32 | The side-effects of `Fn` do not need to be undone. 33 | 34 | TIP: Use this rule to trigger semantic actions during the grammar. 35 | 36 | NOTE: If you need access to values for the semantic action, write a production that produces them and trigger the side-effect in the value callback. 37 | 38 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/eof.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/eof.hpp" 3 | entities: 4 | "lexy::dsl::eof": eof 5 | --- 6 | 7 | [#eof] 8 | == Branch rule `lexy::dsl::eof` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy 13 | { 14 | struct expected_eof {}; 15 | } 16 | 17 | namespace lexy::dsl 18 | { 19 | constexpr _branch-rule_ auto eof; 20 | } 21 | ---- 22 | 23 | [.lead] 24 | `eof` is a {{% branch-rule %}} that matches the end of input (EOF). 25 | 26 | (Branch) Parsing:: 27 | Succeeds if the reader is at the end of the input, without consuming anything. 28 | Errors:: 29 | `lexy::expected_eof`: at the unchanged reader position. It then recovers immediately. 30 | Parse tree:: 31 | Single token node whose range is empty with the {{% docref "lexy::predefined_token_kind" %}} `lexy::eof_token_kind`. 32 | 33 | Parsing `eof` multiple times in sequence has no additional effect: 34 | they all succeed if the first one succeeded and they all fail if the first one failed. 35 | 36 | {{% playground-example eof "Match the empty input" %}} 37 | 38 | {{% playground-example no_trailing "Prevent trailing characters" %}} 39 | 40 | CAUTION: Without `eof`, `lexy` will happily match the prefix of an input only, ignoring any junk characters after it is finished. 41 | 42 | NOTE: It does not skip whitespace before checking for EOF. Use {{% docref "whitespace" "`lexy::dsl::whitespace + eof`" %}} to do that. 43 | 44 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/if.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/if.hpp" 3 | entities: 4 | "lexy::dsl::if_": if_ 5 | --- 6 | :toc: left 7 | 8 | [#if_] 9 | == Rule `lexy::dsl::if_` 10 | 11 | {{% interface %}} 12 | ---- 13 | namespace lexy::dsl 14 | { 15 | constexpr _rule_ auto if_(_branch-rule_ auto branch); 16 | } 17 | ---- 18 | 19 | [.lead] 20 | `if_` is a rule that tries to parse a {{% branch-rule %}}. 21 | 22 | Parsing:: 23 | Tries to parse `branch`. 24 | If that backtracks, succeeds without consuming anything. 25 | Errors:: 26 | All errors raised by `branch` during branch parsing. 27 | The rule then fails if `branch` has failed. 28 | Values:: 29 | All values produced by `branch`. 30 | 31 | {{% playground-example if "Only parse a fraction if preceded by a dot " %}} 32 | 33 | NOTE: `if_(branch)` is functionally equivalent to the {{% docref choice %}} `branch | lexy::dsl::else_`. 34 | 35 | TIP: Use {{% docref "lexy::dsl::opt" %}} if you need a value to indicate that `branch` was not parsed. 36 | 37 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/parse_as.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/parse_as.hpp" 3 | entities: 4 | "lexy::dsl::parse_as": parse_as 5 | --- 6 | 7 | [#parse_as] 8 | == Branch rule `lexy::dsl::parse_as` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy::dsl 13 | { 14 | template 15 | constexpr _rule_ auto parse_as(_rule_ auto rule); 16 | template 17 | constexpr _branch-rule_ auto parse_as(_branch-rule_ auto rule); 18 | } 19 | ---- 20 | 21 | [.lead] 22 | `parse_as` is a {{% branch-rule %}} that parses the rule and ensures that it always produces a value. 23 | 24 | (Branch) Parsing:: 25 | Parses `rule` unchanged. 26 | Errors:: 27 | All errors raised by `rule`. 28 | The rule then fails if `rule` has failed. 29 | Values:: 30 | Value production is done as if the parse action {{% docref "lexy::parse" %}} was used, 31 | regardless of the actual parse action used in the top-level. 32 | If `rule` parses a child production `P`, it invokes the `P::value` callback as necessary to produce a value. 33 | When the rule succeeds, all arguments produced by `rule` are passed to `lexy::construct` and produces that as its single value. 34 | 35 | TIP: Use this rule as a branch condition for a {{% docref "lexy::scan_production" %}}. 36 | 37 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/position.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/position.hpp" 3 | entities: 4 | "lexy::dsl::position": position 5 | --- 6 | 7 | [#position] 8 | == Rule `lexy::dsl::position` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy::dsl 13 | { 14 | constexpr _rule_ auto position; <1> 15 | 16 | constexpr _rule_ auto position(_rule_ auto rule); <2> 17 | constexpr _branch-rule_ auto position(_branch-rule_ auto rule); 18 | } 19 | ---- 20 | 21 | [.lead] 22 | `position` is a rule that produces the current input position without consuming anything. 23 | 24 | (Branch) Parsing:: 25 | 1. Always succeeds without consuming anything. 26 | 2. (Branch) Parses `rule`. 27 | Errors:: 28 | 1. None. 29 | 2. All errors raised by (branch) parsing `rule`. 30 | The rule then fails if `rule` has failed. 31 | Values:: 32 | An iterator to the current position of the reader, followed by all values produced by `rule`. 33 | Parse tree:: 34 | A single token node, whose range is begins and ends at its position, with the {{% docref "lexy::predefined_token_kind" %}} `lexy::position_token_node`, 35 | followed by all nodes produced by `rule`. 36 | 37 | {{% playground-example position "Determine the position of a function declaration" %}} 38 | 39 | NOTE: As a rule, `position` does not do {{% docref whitespace %}} skipping. 40 | If used immediately before a {{% token-rule %}} it will produce the position that is the beginning of this token, 41 | because whitespace skipping is done _after_ token rules. 42 | 43 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/return.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/return.hpp" 3 | entities: 4 | "lexy::dsl::return_": return_ 5 | --- 6 | 7 | [#return_] 8 | == Rule `lexy::dsl::return_` 9 | 10 | {{% interface %}} 11 | ---- 12 | namespace lexy::dsl 13 | { 14 | constexpr _rule_ auto return_; 15 | } 16 | ---- 17 | 18 | [.lead] 19 | `return_` is a rule that terminates parsing of the current production early. 20 | 21 | Requires:: 22 | It is not used inside loops (e.g. {{% docref "lexy::dsl::loop" %}}, {{% docref "lexy::dsl::while_" %}}, {{% docref "lexy::dsl::list" %}}). 23 | Parsing:: 24 | Always succeeds without consuming any input. 25 | Parsing of the current production is then finished. 26 | Errors:: 27 | None. 28 | Values:: 29 | None; but all existing values are immediately parsed to the context, 30 | e.g. the callback is immediately invoked if `lexy::parse()` is used. 31 | 32 | {{% playground-example return "Parse a (simplified) XML element, which can be empty" %}} 33 | 34 | NOTE: See {{< github-example xml >}} for a more complete XML parser. 35 | 36 | -------------------------------------------------------------------------------- /docs/content/reference/dsl/sequence.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | header: "lexy/dsl/sequence.hpp" 3 | entities: 4 | "lexy::dsl::operator+": sequence 5 | "sequence": sequence 6 | --- 7 | 8 | [#sequence] 9 | == Rule `lexy::dsl::operator+` 10 | 11 | {{% interface %}} 12 | ---- 13 | namespace lexy::dsl 14 | { 15 | constexpr _rule_ auto operator+(_rule_ auto lhs, _rule_ auto rhs); 16 | } 17 | ---- 18 | 19 | [.lead] 20 | `operator+` (sequence) is a rule that parses multiple rules one after the other. 21 | 22 | Parsing:: 23 | Parses `lhs`, then parses `rhs`. 24 | Errors:: 25 | All errors raised by `lhs` and/or `rhs`. 26 | The rule fails if either of them has failed. 27 | Values:: 28 | All values produced from `rhs` followed by all values produced by `rhs`. 29 | 30 | {{% playground-example default "Sequence rule is used practically all the time" %}} 31 | 32 | -------------------------------------------------------------------------------- /docs/data/tags/v2022.05.0-beta.toml: -------------------------------------------------------------------------------- 1 | name = "Release 2022.05.0-beta" 2 | url = "https://github.com/foonathan/lexy/releases/tag/v2022.05.0-beta" 3 | download = "https://github.com/foonathan/lexy/releases/download/v2022.05.0-beta/lexy-src.zip" 4 | date = "2022-05-03T14:44:02Z" 5 | prerelease = true 6 | -------------------------------------------------------------------------------- /docs/data/tags/v2022.05.1.toml: -------------------------------------------------------------------------------- 1 | name = "Release 2022.05.1" 2 | url = "https://github.com/foonathan/lexy/releases/tag/v2022.05.1" 3 | download = "https://github.com/foonathan/lexy/releases/download/v2022.05.1/lexy-src.zip" 4 | date = "2022-07-13T11:07:30Z" 5 | prerelease = false 6 | -------------------------------------------------------------------------------- /docs/data/tags/v2022.12.0.toml: -------------------------------------------------------------------------------- 1 | name = "Release 2022.12.0" 2 | url = "https://github.com/foonathan/lexy/releases/tag/v2022.12.0" 3 | download = "https://github.com/foonathan/lexy/releases/download/v2022.12.0/lexy-src.zip" 4 | date = "2022-12-07T10:09:27Z" 5 | prerelease = false 6 | -------------------------------------------------------------------------------- /docs/data/tags/v2022.12.1.toml: -------------------------------------------------------------------------------- 1 | name = "Release 2022.12.1" 2 | url = "https://github.com/foonathan/lexy/releases/tag/v2022.12.1" 3 | download = "https://github.com/foonathan/lexy/releases/download/v2022.12.1/lexy-src.zip" 4 | date = "2023-01-04T11:19:11Z" 5 | prerelease = false 6 | -------------------------------------------------------------------------------- /docs/data/tags/v2025.05.0.toml: -------------------------------------------------------------------------------- 1 | name = "Release 2025.05.0" 2 | url = "https://github.com/foonathan/lexy/releases/tag/v2025.05.0" 3 | download = "https://github.com/foonathan/lexy/releases/download/v2025.05.0/lexy-src.zip" 4 | date = "2025-05-29T18:05:52Z" 5 | prerelease = false 6 | -------------------------------------------------------------------------------- /docs/layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 | 4 |
5 | {{ .Content }} 6 |
7 | 8 |
9 | {{ end }} 10 | -------------------------------------------------------------------------------- /docs/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 | 4 | {{ partial "toc.html" . }} 5 | 6 |
7 |
8 |

{{ .Page.Title }}

9 | 27 |
28 | 29 | {{ .Content }} 30 | 31 |
32 | 33 |
34 | {{ end }} 35 | -------------------------------------------------------------------------------- /docs/layouts/partials/toc.html: -------------------------------------------------------------------------------- 1 | {{ if ne .TableOfContents "" }} 2 | 6 | {{ end }} 7 | 8 | -------------------------------------------------------------------------------- /docs/layouts/reference/list.json.json: -------------------------------------------------------------------------------- 1 | { 2 | {{- range (where .Site.Pages "Section" "reference") -}} 3 | {{- $url := .RelPermalink -}} 4 | {{- range $name, $id := .Params.entities -}} 5 | "{{ $name }}": "{{ $url }}#{{ $id }}", 6 | {{- end -}} 7 | {{- end -}} 8 | "": "" 9 | } 10 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/branch-rule.adoc: -------------------------------------------------------------------------------- 1 | {{- $url := relref . "/reference/dsl/branch#doc" -}} 2 | {{- $.Page.Scratch.SetInMap "see-also" "branch rules" (printf "branch rules" $url) -}} 3 | link:{{ $url }}[branch rule] 4 | {{- printf "" -}} 5 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/char-class-rule.adoc: -------------------------------------------------------------------------------- 1 | {{- $url := relref . "/reference/dsl/char_class#doc" -}} 2 | {{- $.Page.Scratch.SetInMap "see-also" "char class rules" (printf "char class rules" $url) -}} 3 | link:{{ $url }}[char class rule] 4 | {{- printf "" -}} 5 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/docref.adoc: -------------------------------------------------------------------------------- 1 | {{- $name := .Get 0 | lower -}} 2 | {{- $text := .Get 1 | default (printf "`%s`" (.Get 0)) -}} 3 | {{- $found := false -}} 4 | {{- range where .Site.Pages "Section" "reference" -}} 5 | {{- if isset (.Params.entities | default (dict "" "")) $name -}} 6 | {{- $url := printf "%s#%s" .RelPermalink (index .Params.entities $name) -}} 7 | {{- if ne $.Page.Permalink .Permalink -}} 8 | {{- $.Page.Scratch.SetInMap "see-also" $name (printf "%s" $url $name) -}} 9 | {{- end -}} 10 | link:{{ $url }}[{{ $text }}] 11 | {{- $found = true -}} 12 | {{- end -}} 13 | {{- end -}} 14 | {{- if not $found -}} 15 | {{- warnf "%q: Entity %s not found" .Page.File.Path $name -}} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/encoding.adoc: -------------------------------------------------------------------------------- 1 | {{- $url := relref . "/reference/encoding#doc" -}} 2 | {{- $.Page.Scratch.SetInMap "see-also" "rules" (printf "input encodings" $url) -}} 3 | link:{{ $url }}[encoding] 4 | {{- printf "" -}} 5 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/error-callback.adoc: -------------------------------------------------------------------------------- 1 | {{- $url := relref . "/reference/action/validate#error-callback" -}} 2 | {{- $.Page.Scratch.SetInMap "see-also" "rules" (printf "error callback" $url) -}} 3 | link:{{ $url }}[error callback] 4 | {{- printf "" -}} 5 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/experimental.html: -------------------------------------------------------------------------------- 1 |
{{ (resources.Get "icons/beta.svg").Content | safeHTML }}
2 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/github-example.html: -------------------------------------------------------------------------------- 1 | 2 | {{ (resources.Get "icons/github.svg").Content | safeHTML }}{{ .Get 0 }}.cpp 3 | 4 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/godbolt-example.adoc: -------------------------------------------------------------------------------- 1 | {{ $id := .Get 0 }} 2 | {{ $source := ($id | printf "examples/%s.cpp" | resources.Get).Content | chomp }} 3 | 4 | {{ $input := "" }} 5 | {{ $input_resource := ($id | printf "examples/%s.input" | resources.Get) }} 6 | {{ if $input_resource }} 7 | {{ $input = $input_resource.Content | chomp }} 8 | {{ end }} 9 | 10 | {{ $full_source := $source | replaceRE "//({|})\\n?" "" }} 11 | {{ $inline_source := $source | replaceRE "(?s:.*//{\n(.*)//}.*)" "$1"}} 12 | 13 | {{ $lexy := dict "id" "lexy" "version" "trunk" }} 14 | {{ $compiler := dict "id" "clang_trunk" "libs" (slice $lexy) "options" "-std=c++20" }} 15 | 16 | {{ $executor := "" }} 17 | {{ if findRE "^ARGV:" $input }} 18 | {{ $executor = dict "compiler" $compiler "arguments" (replaceRE "^ARGV:" "" $input ) "argumentsVisible" true }} 19 | {{ else }} 20 | {{ $executor = dict "compiler" $compiler "stdin" $input "stdinVisible" (ne $input "") }} 21 | {{ end }} 22 | 23 | {{ $session := dict "id" 1 "language" "c++" "source" $full_source "compilers" (slice) "executors" (slice $executor) }} 24 | {{ $clientstate := dict "sessions" (slice $session) }} 25 | 26 | {{ $clientstate_b64 := replace ($clientstate | jsonify | base64Encode) "/" "%2F" }} 27 | 28 | .{{ .Get 1 }} 29 | ==== 30 | 31 | [.godbolt-example] 32 | .+++{{ (resources.Get "icons/play.svg").Content | safeHTML }}+++ 33 | [source,cpp] 34 | ---- 35 | {{ $inline_source | safeHTML }} 36 | ---- 37 | ==== 38 | 39 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/headerref.adoc: -------------------------------------------------------------------------------- 1 | link:{{ relref . (.Get 0) }}[`lexy/{{ .Get 0 }}.hpp`] 2 | {{- printf "" -}} 3 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/interface.adoc: -------------------------------------------------------------------------------- 1 | .`{{ .Page.Params.header }}` 2 | [source,cpp,subs="+quotes"] 3 | 4 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/literal-rule.adoc: -------------------------------------------------------------------------------- 1 | {{- $url := relref . "/reference/dsl/literal#doc" -}} 2 | {{- $.Page.Scratch.SetInMap "see-also" "literal rules" (printf "literal rules" $url) -}} 3 | link:{{ $url }}[literal rule] 4 | {{- printf "" -}} 5 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/playground-example.adoc: -------------------------------------------------------------------------------- 1 | {{ $id := .Get 0 }} 2 | {{ $source := ($id | printf "playground/%s.cpp" | resources.Get).Content | replaceRE "^// INPUT:.*\n" "" | chomp }} 3 | 4 | .{{ .Get 1 }} 5 | ==== 6 | 7 | [.playground-example] 8 | .+++{{ (resources.Get "icons/play.svg").Content | safeHTML }}+++ 9 | [source,cpp] 10 | ---- 11 | {{ $source | safeHTML }} 12 | ---- 13 | ==== 14 | 15 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/release_list.adoc: -------------------------------------------------------------------------------- 1 | {{ range sort $.Site.Data.tags "date" "desc" }} 2 | +++

{{ .name }} {{ if .prerelease }} {{ (resources.Get "icons/beta.svg").Content | safeHTML }} {{ end }}

+++ 3 | +++{{ (resources.Get "icons/calender.svg").Content | safeHTML }}+++ {{ .date | time.Format "2006-01-02" }} 4 | +++{{ (resources.Get "icons/github.svg").Content | safeHTML }}+++ link:{{ .url }}[Github] 5 | +++{{ (resources.Get "icons/download.svg").Content | safeHTML }}+++ link:{{ .download }}[Download] 6 | +++{{ (resources.Get "icons/license.svg").Content | safeHTML }}+++ link:https://opensource.org/licenses/BSL-1.0/[BSL-1.0] 7 | 8 | ```cmake 9 | include(FetchContent) 10 | FetchContent_Declare(lexy URL {{ .download }}) 11 | FetchContent_MakeAvailable(lexy) 12 | ``` 13 | {{ end }} 14 | 15 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/release_selection.adoc: -------------------------------------------------------------------------------- 1 | ++++ 2 | 7 | ++++ 8 | 9 | ```cmake 10 | include(FetchContent) 11 | FetchContent_Declare(lexy URL https://lexy.foonathan.net/download/lexy-src.zip) 12 | FetchContent_MakeAvailable(lexy) 13 | ``` 14 | 15 | ++++ 16 | 26 | ++++ 27 | 28 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/rule.adoc: -------------------------------------------------------------------------------- 1 | {{- $url := relref . "/reference/dsl/#doc" -}} 2 | {{- $.Page.Scratch.SetInMap "see-also" "rules" (printf "rules" $url) -}} 3 | link:{{ $url }}[rule] 4 | {{- printf "" -}} 5 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/svg.html: -------------------------------------------------------------------------------- 1 | {{ (resources.Get (.Get 0)).Content | safeHTML }} 2 | -------------------------------------------------------------------------------- /docs/layouts/shortcodes/token-rule.adoc: -------------------------------------------------------------------------------- 1 | {{- $url := relref . "/reference/dsl/token#doc" -}} 2 | {{- $.Page.Scratch.SetInMap "see-also" "token rules" (printf "token rules" $url) -}} 3 | link:{{ $url }}[token rule] 4 | {{- printf "" -}} 5 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foonathan/lexy/b33b74b9859d77b16d8a32ef8e4a052f9a55cddc/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/CNAME: -------------------------------------------------------------------------------- 1 | lexy.foonathan.net 2 | -------------------------------------------------------------------------------- /include/lexy/_detail/assert.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | // SPDX-License-Identifier: BSL-1.0 3 | 4 | #ifndef LEXY_DETAIL_ASSERT_HPP_INCLUDED 5 | #define LEXY_DETAIL_ASSERT_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #ifndef LEXY_ENABLE_ASSERT 10 | 11 | // By default, enable assertions if NDEBUG is not defined. 12 | 13 | # if NDEBUG 14 | # define LEXY_ENABLE_ASSERT 0 15 | # else 16 | # define LEXY_ENABLE_ASSERT 1 17 | # endif 18 | 19 | #endif 20 | 21 | #if LEXY_ENABLE_ASSERT 22 | 23 | // We want assertions: use assert() if that's available, otherwise abort. 24 | // We don't use assert() directly as that's not constexpr. 25 | 26 | # if NDEBUG 27 | 28 | # include 29 | # define LEXY_PRECONDITION(Expr) ((Expr) ? void(0) : std::abort()) 30 | # define LEXY_ASSERT(Expr, Msg) ((Expr) ? void(0) : std::abort()) 31 | 32 | # else 33 | 34 | # include 35 | 36 | # define LEXY_PRECONDITION(Expr) ((Expr) ? void(0) : assert(Expr)) 37 | # define LEXY_ASSERT(Expr, Msg) ((Expr) ? void(0) : assert((Expr) && (Msg))) 38 | 39 | # endif 40 | 41 | #else 42 | 43 | // We don't want assertions. 44 | 45 | # define LEXY_PRECONDITION(Expr) static_cast(sizeof(Expr)) 46 | # define LEXY_ASSERT(Expr, Msg) static_cast(sizeof(Expr)) 47 | 48 | #endif 49 | 50 | #endif // LEXY_DETAIL_ASSERT_HPP_INCLUDED 51 | 52 | -------------------------------------------------------------------------------- /include/lexy/_detail/detect.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors 2 | // SPDX-License-Identifier: BSL-1.0 3 | 4 | #ifndef LEXY_DETAIL_DETECT_HPP_INCLUDED 5 | #define LEXY_DETAIL_DETECT_HPP_INCLUDED 6 | 7 | #include 8 | 9 | namespace lexy::_detail 10 | { 11 | template 12 | using void_t = void; 13 | 14 | template