kdl-4.6.0/.cargo_vcs_info.json0000644000000001360000000000100116150ustar { "git": { "sha1": "232d253cbf015741a9d35b02008ef53b5dc99f70" }, "path_in_vcs": "" }kdl-4.6.0/.editorconfig000064400000000000000000000003450072674642500131140ustar 00000000000000# EditorConfig is awesome: https://EditorConfig.org # top-most EditorConfig file root = true [*] indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true kdl-4.6.0/.github/FUNDING.yml000064400000000000000000000001010072674642500136020ustar 00000000000000# These are supported funding model platforms github: [zkat] kdl-4.6.0/.github/workflows/ci.yml000064400000000000000000000020470072674642500151530ustar 00000000000000name: CI on: [push, pull_request] env: RUSTFLAGS: -Dwarnings jobs: fmt_and_docs: name: Check fmt & build docs runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Install Rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable components: rustfmt override: true - name: rustfmt run: cargo fmt --all -- --check - name: docs run: cargo doc --no-deps build_and_test: name: Build & Test runs-on: ${{ matrix.os }} strategy: matrix: rust: [1.56.0, stable] os: [ubuntu-latest, macOS-latest, windows-latest] steps: - uses: actions/checkout@v1 - name: Install Rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.rust }} components: clippy override: true - name: Clippy run: cargo clippy --all -- -D warnings - name: Run tests run: cargo test --all --verbose kdl-4.6.0/.gitignore000064400000000000000000000000250072674642500124220ustar 00000000000000/target Cargo.lock kdl-4.6.0/CHANGELOG.md000064400000000000000000000127600072674642500122540ustar 00000000000000# `kdl` Release Changelog ## 4.6.0 (2022-10-09) ### Features * **errors:** Add better diagnostics for errant plain identifiers in nodes (#59) ([3ddbfec8](https://github.com/kdl-org/kdl-rs/commit/3ddbfec80ec18bc97d9df4004ad262dcdcf79e9b)) ## 4.5.0 (2022-08-31) ### Features * **spans:** add spans to most elements (#57) ([b17ef8e2](https://github.com/kdl-org/kdl-rs/commit/b17ef8e2c61b67cdc632f1772e18f6c7521dcfd8)) ## 4.4.0 (2022-08-18) ### Features * **deps:** bump miette ([8d0f36ce](https://github.com/kdl-org/kdl-rs/commit/8d0f36ceb1c5c1243bae3247b6c86bfa45083f19)) ### Bug Fixes * **formatting:** Fix formatting when decoration is not present (#56) ([2e9c0447](https://github.com/kdl-org/kdl-rs/commit/2e9c0447f9420e37d5fe46d2a42ec7b9f0646d90)) ## 4.3.0 (2022-06-11) ### Features * **fmt:** Add clear_fmt_recursive method (#45) ([cd2d6e42](https://github.com/kdl-org/kdl-rs/commit/cd2d6e42b19b801a43e78256dca1d856367349f4)) ## 4.2.0 (2022-05-11) ### Features * **entry:** Add accessors to entry type. (#43) ([afccf012](https://github.com/kdl-org/kdl-rs/commit/afccf012168dcab1de89f3737014ee8ee037785b)) ## 4.1.1 (2022-04-28) ### Bug Fixes * **compliance:** pull in spec test suite and fix issues (#40) ([58a40fdf](https://github.com/kdl-org/kdl-rs/commit/58a40fdf487b303f7466c93d84a4cd8a5665aa24)) ## 4.1.0 (2022-04-24) ### Features * **fmt:** shiny new comment-preserving formatter! (#38) ([12d373a1](https://github.com/kdl-org/kdl-rs/commit/12d373a1e0de6533e7722e3ecc69e7ddc0e59db9)) ## 4.0.0 (2022-04-23) Hello again! kdl-rs 4.0.0 is a _complete_ rewrite, featuring a full-fledged "document-oriented" parser: that is, formatting, whitespace, comments, etc, are all preserved and can be programmatically manipulated. KDL documents are fully round-trippable, without losing any of that human-written content! This crate will, for the time being, not include a serde-based parser, but there's also crates like [`knuffel`](https://crates.io/crates/knuffel) and [`kaydle`](https://crates.io/crates/kaydle) now that do probide serde (or serde-like) functionality. You should definitely check those out if you're looking for that kind of workflow! Please give this version a whirl if you've been curious about using KDL for your own projects, and let me know what can be improved, or even what you love about it! ### Features * **api:** complete rewrite into document-oriented parser (#29) ([364ea617](https://github.com/kdl-org/kdl-rs/commit/364ea6173c0bcfc2f5e4b21e19120179f6a5c5ed)) * **BREAKING CHANGE**: Completely new API and bumped MSRV to 1.56.0. * **tests:** add test for kdl-schema.kdl (#30) ([ad34cfd9](https://github.com/kdl-org/kdl-rs/commit/ad34cfd93a9e6d8018b8086821a3463b764fb363)) * **types:** add type annotation support (#31) ([16c82f1e](https://github.com/kdl-org/kdl-rs/commit/16c82f1ec18c221b0d98dfcfb805ed3642354f5b)) * **errors:** improve parsing errors and fix some bugs (#33) ([8ed6a5cd](https://github.com/kdl-org/kdl-rs/commit/8ed6a5cd068e60de03a0e14493383f2515b98f81)) * **clear_fmt:** add methods to clear formatting and reset it to default ([892bf06e](https://github.com/kdl-org/kdl-rs/commit/892bf06e69c746ea9711fe33979f28f937329672)) * **errors:** overhauled error reporting a ton ([d63f336d](https://github.com/kdl-org/kdl-rs/commit/d63f336d188eb15a4bd8c870e7ee37617923270a)) * **len:** add APIs to calculate component lengths (#36) ([177c42ca](https://github.com/kdl-org/kdl-rs/commit/177c42cae75d8a0d9985c26ea28cb4f1cf7077de)) ### Bug Fixes * **parse:** small parser tweaks + more tests ([1a8eb351](https://github.com/kdl-org/kdl-rs/commit/1a8eb351685dc368c55d992d719e6bad34398df2)) * **api:** remove obsolete type ([40b04418](https://github.com/kdl-org/kdl-rs/commit/40b04418c9dc9a8363c000e19bc22e54c0dae7e9)) ## 3.0.0 (2021-09-16) ### Features * **spec:** update parser to handle KDL 1.0.0 ([f811c5c8](https://github.com/kdl-org/kdl-rs/commit/f811c5c89c18cb02cc3e7bdd8c872ea42308ae3e)) * **BREAKING CHANGE**: Various things have changed in the process of moving to KDL 1.0.0. Please test your stuff ## 2.0.0 (2021-09-16) ### Features * **license:** change license to Apache-2.0 ([0dbf75c7](https://github.com/kdl-org/kdl-rs/commit/0dbf75c78eb918b6966aae27fb1d7591791f15de)) * **BREAKING CHANGE**: This is a significant licensing change. Please review. ## 1.1.0 (2021-05-08) It's been a while! This release brings kdl-rs much closer in sync with the actual spec. #### Bug Fixes * **deps:** Remove nom dependency on `bitvec` and `lexical` (#14) ([9bc5363b](https://github.com/kdl/kdl-rs/commit/9bc5363bb5b8e4ae39e250f2facbfcdf4557f11b)) * **numbers:** Fix parsing of non-integer and non-decimal numbers (#13) ([c1b7c25c](https://github.com/kdl/kdl-rs/commit/c1b7c25c0095ac2bd8acf06f6834c734a42b4470)) #### Features * **display:** implemented Display for KdlNode (#6) ([b8c8b527](https://github.com/kdl/kdl-rs/commit/b8c8b52748747d80215ee0c3dea73e260e133af2)) * **docs:** Add documentation for the entire crate (#16) ([94190697](https://github.com/kdl/kdl-rs/commit/94190697d8ad676f9b879dcc90f8eb03266c3ef8)) * **identifier:** much larger character set for identifiers (not just alphanumeric), to match spec more closely (#7) ([95a1ee3e](https://github.com/kdl/kdl-rs/commit/95a1ee3e57156507c3bf8a8035017d4836e49a01)) ## 1.0.0 (2020-12-19) Initial Release! � kdl-4.6.0/CODE_OF_CONDUCT.md000064400000000000000000000154610072674642500132430ustar 00000000000000# Code of Conduct ## When Something Happens If you see behavoir that makes you feel unsafe or unwelcome or otherwise uncomfortable, follow these steps: 1. Let the person know that what they did is not appropriate and ask them to stop and/or edit their message(s) or commits. 2. That person should immediately stop the behavior and correct the issue. 3. If this doesn’t happen, or if you're uncomfortable speaking up, [contact the maintainers](#contacting-maintainers). 4. As soon as available, a maintainer will look into the issue, and take [further action (see below)](#further-enforcement), starting with a warning, then temporary block, then long-term repo or organization ban. **The maintainer team will prioritize the well-being and comfort of those affected over the comfort of the offending party.** See [some examples below](#enforcement-examples). ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers of this project pledge to making participation in our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, technical preferences, nationality, personal appearance, race, religion, or sexual identity and orientation. This commitment means that inappropriate behavior can lead to intervention. This includes our intention to address issues with [missing stairs](https://en.wikipedia.org/wiki/Missing_stair) who may not have explicitly violated any written-down rules but might still be disrupting the community. ## Scope This Code of Conduct applies both within spaces involving this project and in other spaces involving community members. This includes the repository, its Pull Requests and Issue tracker, its Twitter community, private email communications in the context of the project, and any events where members of the project are participating, as well as adjacent communities and venues affecting the project's members. Depending on the violation, the maintainers may decide that violations of this code of conduct that have happened outside of the scope of the community may deem an individual unwelcome, and take appropriate action to maintain the comfort and safety of its members. ## Contacting Maintainers - [Kat Marchán ](mailto:coc@zkat.tech) ## Further Enforcement If you've already followed the [initial enforcement steps](#enforcement), these are the steps maintainers will take for further enforcement, as needed: 1. Repeat the request to stop. 2. If the person doubles down, they will have offending messages removed or edited by a maintainers given an official warning. The PR or Issue may be locked. 3. If the behavior continues or is repeated later, the person will be blocked from participating for 24 hours. 4. If the behavior continues or is repeated after the temporary block, a long-term (6-12mo) ban will be used. On top of this, maintainers may remove any offending messages, images, contributions, etc, as they deem necessary. Maintainers reserve full rights to skip any of these steps, at their discretion, if the violation is considered to be a serious and/or immediate threat to the health and well-being of members of the community. These include any threats, serious physical or verbal attacks, and other such behavior that would be completely unacceptable in any social setting that puts our members at risk. Members expelled from events or venues with any sort of paid attendance will not be refunded. ## Who Watches the Watchers? Maintainers and other leaders who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. These may include anything from removal from the maintainer team to a permanent ban from the community. Additionally, as a project hosted on both GitHub, [their Community Guidielines may be applied to maintainers of this project](https://help.github.com/articles/github-community-guidelines/), externally of this project's procedures. ## Enforcement Examples ### The Best Case The vast majority of situations work out like this. This interaction is common, and generally positive. > Alex: "Yeah I used X and it was really crazy!" > Patt (not a maintainer): "Hey, could you not use that word? What about 'ridiculous' instead?" > Alex: "oh sorry, sure." -> edits old comment to say "it was really confusing!" ### The Maintainer Case Sometimes, though, you need to get maintainers involved. Maintainers will do their best to resolve conflicts, but people who were harmed by something **will take priority**. > Patt: "Honestly, sometimes I just really hate using $library and anyone who uses it probably sucks at their job." > Alex: "Whoa there, could you dial it back a bit? There's a CoC thing about attacking folks' tech use like that." > Patt: "I'm not attacking anyone, what's your problem?" > Alex: "@maintainers hey uh. Can someone look at this issue? Patt is getting a bit aggro. I tried to nudge them about it, but nope." > KeeperOfCommitBits: (on issue) "Hey Patt, maintainer here. Could you tone it down? This sort of attack is really not okay in this space." > Patt: "Leave me alone I haven't said anything bad wtf is wrong with you." > KeeperOfCommitBits: (deletes user's comment), "@patt I mean it. Please refer to the CoC over at (URL to this CoC) if you have questions, but you can consider this an actual warning. I'd appreciate it if you reworded your messages in this thread, since they made folks there uncomfortable. Let's try and be kind, yeah?" > Patt: "@keeperofbits Okay sorry. I'm just frustrated and I'm kinda burnt out and I guess I got carried away. I'll DM Alex a note apologizing and edit my messages. Sorry for the trouble." > KeeperOfCommitBits: "@patt Thanks for that. I hear you on the stress. Burnout sucks :/. Have a good one!" ### The Nope Case > PepeTheFrog🐸: "Hi, I am a literal actual nazi and I think white supremacists are quite fashionable." > Patt: "NOOOOPE. OH NOPE NOPE." > Alex: "JFC NO. NOPE. @keeperofbits NOPE NOPE LOOK HERE" > KeeperOfCommitBits: "👀 Nope. NOPE NOPE NOPE. 🔥" > PepeTheFrog🐸 has been banned from all organization or user repositories belonging to KeeperOfCommitBits. ## Attribution This Code of Conduct was generated using [WeAllJS Code of Conduct Generator](https://npm.im/weallbehave), which is based on the [WeAllJS Code of Conduct](https://wealljs.org/code-of-conduct), which is itself based on [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4), and the LGBTQ in Technology Slack [Code of Conduct](http://lgbtq.technology/coc.html). kdl-4.6.0/Cargo.lock0000644000000060620000000000100075740ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "kdl" version = "4.6.0" dependencies = [ "miette", "nom", "thiserror", ] [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "miette" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28d6092d7e94a90bb9ea8e6c26c99d5d112d49dda2afdb4f7ea8cf09e1a5a6d" dependencies = [ "miette-derive", "once_cell", "thiserror", "unicode-width", ] [[package]] name = "miette-derive" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f2485ed7d1fe80704928e3eb86387439609bd0c6bb96db8208daa364cfd1e09" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "once_cell" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "proc-macro2" version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] name = "syn" version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "thiserror" version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-width" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" kdl-4.6.0/Cargo.toml0000644000000021640000000000100076160ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "kdl" version = "4.6.0" authors = [ "Kat Marchán ", "KDL Community", ] description = "Document-oriented KDL parser and API. Allows formatting/whitespace/comment-preserving parsing and modification of KDL text." homepage = "https://kdl.dev" readme = "README.md" keywords = [ "kdl", "document", "serialization", "config", ] license = "Apache-2.0" repository = "https://github.com/kdl-org/kdl-rs" resolver = "2" [dependencies.miette] version = "5.3.0" [dependencies.nom] version = "7.1.1" default-features = false [dependencies.thiserror] version = "1.0.30" [features] default = ["span"] span = [] kdl-4.6.0/Cargo.toml.orig0000644000000011130000000000100105460ustar [package] name = "kdl" version = "4.6.0" description = "Document-oriented KDL parser and API. Allows formatting/whitespace/comment-preserving parsing and modification of KDL text." authors = ["Kat Marchán ", "KDL Community"] license = "Apache-2.0" readme = "README.md" homepage = "https://kdl.dev" repository = "https://github.com/kdl-org/kdl-rs" keywords = ["kdl", "document", "serialization", "config"] edition = "2021" [features] default = ["span"] span = [] [dependencies] miette = "5.3.0" nom = { version = "7.1.1", default-features = false } thiserror = "1.0.30" kdl-4.6.0/Cargo.toml.orig000064400000000000000000000011130072674642500133200ustar 00000000000000[package] name = "kdl" version = "4.6.0" description = "Document-oriented KDL parser and API. Allows formatting/whitespace/comment-preserving parsing and modification of KDL text." authors = ["Kat Marchán ", "KDL Community"] license = "Apache-2.0" readme = "README.md" homepage = "https://kdl.dev" repository = "https://github.com/kdl-org/kdl-rs" keywords = ["kdl", "document", "serialization", "config"] edition = "2021" [features] default = ["span"] span = [] [dependencies] miette = "5.3.0" nom = { version = "7.1.1", default-features = false } thiserror = "1.0.30" kdl-4.6.0/LICENSE000064400000000000000000000246540072674642500114550ustar 00000000000000Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] Kat Marchán Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.kdl-4.6.0/Makefile.toml000064400000000000000000000005750072674642500130560ustar 00000000000000[tasks.changelog] workspace=false install_crate="git-cliff" command = "git-cliff" args = ["--prepend", "CHANGELOG.md", "-u", "--tag", "${@}"] [tasks.release] workspace=false install_crate="cargo-release" command = "cargo" args = ["release", "--workspace", "${@}"] [tasks.readme] workspace=false install_crate="cargo-readme" command = "cargo" args = ["readme", "-o", "README.md"] kdl-4.6.0/README.md000064400000000000000000000074760072674642500117320ustar 00000000000000# `kdl` `kdl` is a "document-oriented" parser and API for the [KDL Document Language](https://kdl.dev), a node-based, human-friendly configuration and serialization format. Unlike serde-based implementations, this crate preserves formatting when editing, as well as when inserting or changing values with custom formatting. This is most useful when working with human-maintained KDL files. You can think of this crate as [`toml_edit`](https://crates.io/crates/toml_edit), but for KDL. If you don't care about formatting or programmatic manipulation, you might check out [`knuffel`](https://crates.io/crates/knuffel) instead for serde (or serde-like) parsing. ### Example ```rust use kdl::KdlDocument; let doc_str = r#" hello 1 2 3 world prop="value" { child 1 child 2 } "#; let doc: KdlDocument = doc_str.parse().expect("failed to parse KDL"); assert_eq!( doc.get_args("hello"), vec![&1.into(), &2.into(), &3.into()] ); assert_eq!( doc.get("world").map(|node| &node["prop"]), Some(&"value".into()) ); // Documents fully roundtrip: assert_eq!(doc.to_string(), doc_str); ``` ### Controlling Formatting By default, everything is created with default formatting. You can parse items manually to provide custom representations, comments, etc: ```rust let node_str = r#" // indented comment "formatted" 1 /* comment */ \ 2; "#; let mut doc = kdl::KdlDocument::new(); doc.nodes_mut().push(node_str.parse().unwrap()); assert_eq!(&doc.to_string(), node_str); ``` [`KdlDocument`], [`KdlNode`], [`KdlEntry`], and [`KdlIdentifier`] can all be parsed and managed this way. ### Error Reporting [`KdlError`] implements [`miette::Diagnostic`] and can be used to display detailed, pretty-printed diagnostic messages when using [`miette::Result`] and the `"fancy"` feature flag for `miette`: ```toml # Cargo.toml [dependencies] miette = { version = "x.y.z", features = ["fancy"] } ``` ```rust fn main() -> miette::Result<()> { "foo 1.".parse::()?; Ok(()) } ``` This will display a message like: ``` Error: × Expected valid value. ╭──── 1 │ foo 1. · ─┬ · ╰── invalid float ╰──── help: Floating point numbers must be base 10, and have numbers after the decimal point. ``` ### Quirks #### Properties Multiple properties with the same name are allowed, and all duplicated **will be preserved**, meaning those documents will correctly round-trip. When using `node.get()`/`node["key"]` & company, the _last_ property with that name's value will be returned. #### Numbers KDL itself does not specify a particular representation for numbers and accepts just about anything valid, no matter how large and how small. This means a few things: * Numbers without a decimal point are interpreted as u64. * Numbers with a decimal point are interpreted as f64. * Floating point numbers that evaluate to f64::INFINITY or f64::NEG_INFINITY or NaN will be represented as such in the values, instead of the original numbers. * A similar restriction applies to overflowed u64 values. * The original _representation_ of these numbers will be preserved, unless you `doc.fmt()`, in which case the original representation will be thrown away and the actual value will be used when serializing. ### License The code in this repository is covered by [the Apache-2.0 License](LICENSE.md). [`KdlDocument`]: https://docs.rs/kdl/latest/kdl/struct.KdlDocument.html [`KdlNode`]: https://docs.rs/kdl/latest/kdl/struct.KdlNode.html [`KdlEntry`]: https://docs.rs/kdl/latest/kdl/struct.KdlEntry.html [`KdlIdentifier`]: https://docs.rs/kdl/latest/kdl/struct.KdlIdentifier.html [`KdlError`]: https://docs.rs/kdl/latest/kdl/struct.KdlError.html [`miette::Diagnostic`]: https://docs.rs/miette/latest/miette/trait.Diagnostic.html [`miette::Result`]: https://docs.rs/miette/latest/miette/type.Result.html kdl-4.6.0/README.tpl000064400000000000000000000010200072674642500121040ustar 00000000000000# `{{crate}}` {{readme}} [`KdlDocument`]: https://docs.rs/kdl/latest/kdl/struct.KdlDocument.html [`KdlNode`]: https://docs.rs/kdl/latest/kdl/struct.KdlNode.html [`KdlEntry`]: https://docs.rs/kdl/latest/kdl/struct.KdlEntry.html [`KdlIdentifier`]: https://docs.rs/kdl/latest/kdl/struct.KdlIdentifier.html [`KdlError`]: https://docs.rs/kdl/latest/kdl/struct.KdlError.html [`miette::Diagnostic`]: https://docs.rs/miette/latest/miette/trait.Diagnostic.html [`miette::Result`]: https://docs.rs/miette/latest/miette/type.Result.html kdl-4.6.0/cliff.toml000064400000000000000000000035520072674642500124220ustar 00000000000000# configuration file for git-cliff (0.1.0) [changelog] # changelog header header = """ # `kdl` Release Changelog """ # template for the changelog body # https://tera.netlify.app/docs/#introduction body = """ {% if version %}\ ## {{ version | replace(from="v", to="") }} ({{ timestamp | date(format="%Y-%m-%d") }}) {% else %}\ ## Unreleased {% endif %}\ {% for group, commits in commits | filter(attribute="scope") | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} {% if commit.scope %}\ * **{{ commit.scope }}:** {{ commit.message }} ([{{ commit.id | truncate(length=8, end="") }}](https://github.com/kdl-org/kdl-rs/commit/{{ commit.id }})) {%- if commit.breaking %} * **BREAKING CHANGE**: {{ commit.breaking_description }} {%- endif %}\ {% endif %}\ {% endfor %} {% endfor %} """ # remove the leading and trailing whitespace from the template trim = false # changelog footer # footer = """ # # """ [git] # allow only conventional commits # https://www.conventionalcommits.org conventional_commits = true # regex for parsing and grouping commits commit_parsers = [ { message = "^feat*", group = "Features"}, { message = "^fix*", group = "Bug Fixes"}, { message = "^doc*", group = "Documentation"}, { message = "^perf*", group = "Performance"}, { message = "^refactor*", group = "Refactor"}, { message = "^style*", group = "Styling"}, { message = "^test*", group = "Testing"}, { message = "^chore\\(release\\): prepare for*", skip = true}, { message = "^chore*", group = "Miscellaneous Tasks"}, { body = ".*security", group = "Security"}, ] # filter out the commits that are not matched by commit parsers filter_commits = true # glob pattern for matching git tags # tag_pattern = "v?[0-9]*" # regex for skipping tags # skip_tags = "v0.1.0-beta.1" kdl-4.6.0/src/document.rs000064400000000000000000000513250072674642500134160ustar 00000000000000#[cfg(feature = "span")] use miette::SourceSpan; use std::{fmt::Display, str::FromStr}; use crate::{parser, KdlError, KdlNode, KdlValue}; /// Represents a KDL /// [`Document`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#document). /// /// This type is also used to manage a [`KdlNode`]'s [`Children /// Block`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#children-block), /// when present. /// /// # Examples /// /// The easiest way to create a `KdlDocument` is to parse it: /// ```rust /// # use kdl::KdlDocument; /// let kdl: KdlDocument = "foo 1 2 3\nbar 4 5 6".parse().expect("parse failed"); /// ``` #[derive(Debug, Clone)] pub struct KdlDocument { pub(crate) leading: Option, pub(crate) nodes: Vec, pub(crate) trailing: Option, #[cfg(feature = "span")] pub(crate) span: SourceSpan, } impl PartialEq for KdlDocument { fn eq(&self, other: &Self) -> bool { self.leading == other.leading && self.nodes == other.nodes && self.trailing == other.trailing // Intentionally omitted: self.span == other.span } } impl Default for KdlDocument { fn default() -> Self { Self { leading: Default::default(), nodes: Default::default(), trailing: Default::default(), #[cfg(feature = "span")] span: SourceSpan::from(0..0), } } } impl KdlDocument { /// Creates a new Document. pub fn new() -> Self { Default::default() } /// Gets this document's span. /// /// This value will be properly initialized when created via [`KdlDocument::parse`] /// but may become invalidated if the document is mutated. We do not currently /// guarantee this to yield any particularly consistent results at that point. #[cfg(feature = "span")] pub fn span(&self) -> &SourceSpan { &self.span } /// Gets a mutable reference to this document's span. #[cfg(feature = "span")] pub fn span_mut(&mut self) -> &mut SourceSpan { &mut self.span } /// Sets this document's span. #[cfg(feature = "span")] pub fn set_span(&mut self, span: impl Into) { self.span = span.into(); } /// Gets the first child node with a matching name. pub fn get(&self, name: &str) -> Option<&KdlNode> { self.nodes.iter().find(move |n| n.name().value() == name) } /// Gets a reference to the first child node with a matching name. pub fn get_mut(&mut self, name: &str) -> Option<&mut KdlNode> { self.nodes .iter_mut() .find(move |n| n.name().value() == name) } /// Gets the first argument (value) of the first child node with a /// matching name. This is a shorthand utility for cases where a document /// is being used as a key/value store. /// /// # Examples /// /// Given a document like this: /// ```kdl /// foo 1 /// bar false /// ``` /// /// You can fetch the value of `foo` in a single call like this: /// ```rust /// # use kdl::{KdlDocument, KdlValue}; /// # let doc: KdlDocument = "foo 1\nbar false".parse().unwrap(); /// assert_eq!(doc.get_arg("foo"), Some(&1.into())); /// ``` pub fn get_arg(&self, name: &str) -> Option<&KdlValue> { self.get(name) .and_then(|node| node.get(0)) .map(|e| e.value()) } /// Gets the all node arguments (value) of the first child node with a /// matching name. This is a shorthand utility for cases where a document /// is being used as a key/value store and the value is expected to be /// array-ish. /// /// If a node has no arguments, this will return an empty array. /// /// # Examples /// /// Given a document like this: /// ```kdl /// foo 1 2 3 /// bar false /// ``` /// /// You can fetch the arguments for `foo` in a single call like this: /// ```rust /// # use kdl::{KdlDocument, KdlValue}; /// # let doc: KdlDocument = "foo 1 2 3\nbar false".parse().unwrap(); /// assert_eq!(doc.get_args("foo"), vec![&1.into(), &2.into(), &3.into()]); /// ``` pub fn get_args(&self, name: &str) -> Vec<&KdlValue> { self.get(name) .map(|n| n.entries()) .unwrap_or_default() .iter() .filter(|e| e.name().is_none()) .map(|e| e.value()) .collect() } /// Gets a mutable reference to the first argument (value) of the first /// child node with a matching name. This is a shorthand utility for cases /// where a document is being used as a key/value store. pub fn get_arg_mut(&mut self, name: &str) -> Option<&mut KdlValue> { self.get_mut(name) .and_then(|node| node.get_mut(0)) .map(|e| e.value_mut()) } /// This utility makes it easy to interact with a KDL convention where /// child nodes named `-` are treated as array-ish values. /// /// # Examples /// /// Given a document like this: /// ```kdl /// foo { /// - 1 /// - 2 /// - false /// } /// ``` /// /// You can fetch the dashed child values of `foo` in a single call like this: /// ```rust /// # use kdl::{KdlDocument, KdlValue}; /// # let doc: KdlDocument = "foo {\n - 1\n - 2\n - false\n}".parse().unwrap(); /// assert_eq!(doc.get_dash_vals("foo"), vec![&1.into(), &2.into(), &false.into()]); /// ``` pub fn get_dash_vals(&self, name: &str) -> Vec<&KdlValue> { self.get(name) .and_then(|n| n.children()) .map(|doc| doc.nodes()) .unwrap_or_default() .iter() .filter(|e| e.name().value() == "-") .map(|e| e.get(0)) .filter(|v| v.is_some()) .map(|v| v.unwrap().value()) .collect() } /// Returns a reference to this document's child nodes. pub fn nodes(&self) -> &[KdlNode] { &self.nodes } /// Returns a mutable reference to this document's child nodes. pub fn nodes_mut(&mut self) -> &mut Vec { &mut self.nodes } /// Gets leading text (whitespace, comments) for this KdlDocument. pub fn leading(&self) -> Option<&str> { self.leading.as_deref() } /// Sets leading text (whitespace, comments) for this KdlDocument. pub fn set_leading(&mut self, leading: impl Into) { self.leading = Some(leading.into()); } /// Gets trailing text (whitespace, comments) for this KdlDocument. pub fn trailing(&self) -> Option<&str> { self.trailing.as_deref() } /// Sets trailing text (whitespace, comments) for this KdlDocument. pub fn set_trailing(&mut self, trailing: impl Into) { self.trailing = Some(trailing.into()); } /// Length of this document when rendered as a string. pub fn len(&self) -> usize { format!("{}", self).len() } /// Returns true if this document is completely empty (including whitespace) pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears leading and trailing text (whitespace, comments). `KdlNode`s in /// this document will be unaffected. /// /// If you need to clear the `KdlNode`s, use [`Self::clear_fmt_recursive`]. pub fn clear_fmt(&mut self) { self.leading = None; self.trailing = None; } /// Clears leading and trailing text (whitespace, comments), also clearing /// all the `KdlNode`s in the document. pub fn clear_fmt_recursive(&mut self) { self.clear_fmt(); for node in self.nodes.iter_mut() { node.clear_fmt_recursive(); } } /// Auto-formats this Document, making everything nice while preserving /// comments. pub fn fmt(&mut self) { self.fmt_impl(0, false); } /// Formats the document and removes all comments from the document. pub fn fmt_no_comments(&mut self) { self.fmt_impl(0, true); } } impl Display for KdlDocument { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.stringify(f, 0) } } impl KdlDocument { pub(crate) fn fmt_impl(&mut self, indent: usize, no_comments: bool) { if let Some(s) = self.leading.as_mut() { crate::fmt::fmt_leading(s, indent, no_comments); } let mut has_nodes = false; for node in &mut self.nodes { has_nodes = true; node.fmt_impl(indent, no_comments); } if let Some(s) = self.trailing.as_mut() { crate::fmt::fmt_trailing(s, no_comments); if !has_nodes { s.push('\n'); } } } pub(crate) fn stringify( &self, f: &mut std::fmt::Formatter<'_>, indent: usize, ) -> std::fmt::Result { if let Some(leading) = &self.leading { write!(f, "{}", leading)?; } for node in &self.nodes { node.stringify(f, indent)?; if node.trailing.is_none() { writeln!(f)?; } } if let Some(trailing) = &self.trailing { write!(f, "{}", trailing)?; } Ok(()) } } impl IntoIterator for KdlDocument { type Item = KdlNode; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.nodes.into_iter() } } impl FromStr for KdlDocument { type Err = KdlError; fn from_str(input: &str) -> Result { let kdl_parser = parser::KdlParser::new(input); kdl_parser.parse(parser::document(&kdl_parser)) } } #[cfg(test)] mod test { #[cfg(feature = "span")] use crate::KdlIdentifier; use crate::{KdlEntry, KdlValue}; use super::*; #[test] fn canonical_clear_fmt() -> miette::Result<()> { let left_src = r#" // There is a node here first_node /*with cool comments, too */ param=1.03e2 /-"commented" "argument" { // With nested nodes too nested 1 2 3 nested_2 "hi" "world" // this one is cool } second_node param=153 { nested one=1 two=2; }"#; let right_src = r#" first_node param=103.0 "argument" { // Different indentation, because // Why not nested 1 2 3 nested_2 "hi" /* actually, "hello" */ "world" } // There is a node here second_node /* This time, the comment is here */ param=153 { nested one=1 two=2 }"#; let mut left_doc: KdlDocument = left_src.parse()?; let mut right_doc: KdlDocument = right_src.parse()?; assert_ne!(left_doc, right_doc); left_doc.clear_fmt_recursive(); right_doc.clear_fmt_recursive(); assert_eq!(left_doc, right_doc); Ok(()) } #[test] fn parsing() -> miette::Result<()> { let src = " // This is the first node foo 1 2 \"three\" null true bar=\"baz\" { - 1 - 2 - \"three\" (mytype)something (\"name\")\"else\"\r } null_id null_prop=null true_id true_prop=null +false true bar \"indented\" // trailing whitespace after this\t /* Some random comment */ a; b; c; /-commented \"node\" another /*foo*/ \"node\" /-1 /*bar*/ null; final;"; let mut doc: KdlDocument = src.parse()?; assert_eq!(doc.leading, Some("".into())); assert_eq!(doc.get_arg("foo"), Some(&1.into())); assert_eq!( doc.get_dash_vals("foo"), vec![&1.into(), &2.into(), &"three".into()] ); let foo = doc.get("foo").expect("expected a foo node"); assert_eq!(foo.leading, Some("\n// This is the first node\n".into())); assert_eq!(&foo[2], &"three".into()); assert_eq!(&foo["bar"], &"baz".into()); assert_eq!( foo.children().unwrap().get_arg("something"), Some(&"else".into()) ); assert_eq!(doc.get_arg("another"), Some(&"node".into())); let null = doc.get("null_id").expect("expected a null_id node"); assert_eq!(&null["null_prop"], &KdlValue::Null); let tru = doc.get("true_id").expect("expected a true_id node"); assert_eq!(&tru["true_prop"], &KdlValue::Null); let plusfalse = doc.get("+false").expect("expected a +false node"); assert_eq!(&plusfalse[0], &KdlValue::Bool(true)); let bar = doc.get("bar").expect("expected a bar node"); assert_eq!( format!("{}", bar), "\n bar \"indented\" // trailing whitespace after this\t\n" ); let a = doc.get("a").expect("expected a node"); assert_eq!( format!("{}", a), "/*\nSome random comment\n */\n\na; ".to_string() ); let b = doc.get("b").expect("expected a node"); assert_eq!(format!("{}", b), "b; ".to_string()); // Round-tripping works. assert_eq!(format!("{}", doc), src); // Programmatic manipulation works. let mut node: KdlNode = "new\n".parse()?; // Manual entry parsing preserves formatting/reprs. node.push("\"blah\"=0xDEADbeef".parse::()?); doc.nodes_mut().push(node); assert_eq!( format!("{}", doc), format!("{}new \"blah\"=0xDEADbeef\n", src) ); Ok(()) } #[test] fn construction() { let mut doc = KdlDocument::new(); doc.nodes_mut().push(KdlNode::new("foo")); let mut bar = KdlNode::new("bar"); bar.insert("prop", "value"); bar.push(1); bar.push(2); bar.push(false); bar.push(KdlValue::Null); let subdoc = bar.ensure_children(); subdoc.nodes_mut().push(KdlNode::new("barchild")); doc.nodes_mut().push(bar); doc.nodes_mut().push(KdlNode::new("baz")); assert_eq!( r#"foo bar prop="value" 1 2 false null { barchild } baz "#, format!("{}", doc) ); } #[test] fn fmt() -> miette::Result<()> { let mut doc: KdlDocument = r#" /* x */ foo 1 "bar"=0xDEADbeef { child1 1 ; // child 2 comment child2 2 // comment child3 " string\t" \ { /* multiline*/ inner1 \ r"value" \ ; inner2 \ //comment { inner3 } } } // trailing comment here "# .parse()?; KdlDocument::fmt(&mut doc); print!("{}", doc); assert_eq!( doc.to_string(), r#"/* x */ foo 1 bar=0xdeadbeef { child1 1 // child 2 comment child2 2 // comment child3 "\n\n string\t" { /* multiline*/ inner1 r"value" inner2 { inner3 } } } // trailing comment here"# ); Ok(()) } #[test] fn simple_fmt() -> miette::Result<()> { let mut doc: KdlDocument = "a { b { c { }; }; }".parse().unwrap(); KdlDocument::fmt(&mut doc); print!("{}", doc); assert_eq!( doc.to_string(), r#"a { b { c { } } } "# ); Ok(()) } #[cfg(feature = "span")] fn check_spans_for_doc(doc: &KdlDocument, source: &impl miette::SourceCode) { for node in doc.nodes() { check_spans_for_node(node, source); } } #[cfg(feature = "span")] fn check_spans_for_node(node: &KdlNode, source: &impl miette::SourceCode) { check_span_for_ident(node.name(), source); if let Some(ty) = node.ty() { check_span_for_ident(ty, source); } for entry in node.entries() { if let Some(name) = entry.name() { check_span_for_ident(name, source); } if let Some(ty) = entry.ty() { check_span_for_ident(ty, source); } if let Some(repr) = entry.value_repr() { if entry.name().is_none() && entry.ty().is_none() { check_span(repr, entry.span(), source); } } } if let Some(children) = node.children() { check_spans_for_doc(children, source); } } #[cfg(feature = "span")] #[track_caller] fn check_span_for_ident(ident: &KdlIdentifier, source: &impl miette::SourceCode) { if let Some(repr) = ident.repr() { check_span(repr, ident.span(), source); } else { check_span(ident.value(), ident.span(), source); } } #[cfg(feature = "span")] #[track_caller] fn check_span(expected: &str, span: &SourceSpan, source: &impl miette::SourceCode) { let span = source.read_span(span, 0, 0).unwrap(); let span = std::str::from_utf8(span.data()).unwrap(); assert_eq!(span, expected); } #[cfg(feature = "span")] #[test] fn span_test() -> miette::Result<()> { let input = r####" this { is (a)"cool" document="to" read=(int)5 10.1 (u32)0x45 and x="" { "it" /*shh*/ "has"="💯" r##"the"## Best🎊est "syntax ever" } "yknow?" 0x10 } // that's nice inline { time; to; live "our" "dreams"; "y;all"; } "####; let doc: KdlDocument = input.parse().unwrap(); // First check that all the identity-spans are correct check_spans_for_doc(&doc, &input); // Now check some more interesting concrete spans // The whole document should presumably be "the input" again? check_span(input, doc.span(), &input); // This one-liner node should be the whole line without leading whitespace let is_node = doc .get("this") .unwrap() .children() .unwrap() .get("is") .unwrap(); check_span( r##"is (a)"cool" document="to" read=(int)5 10.1 (u32)0x45"##, is_node.span(), &input, ); // Some simple with/without type hints check_span(r#"(a)"cool""#, is_node.get(0).unwrap().span(), &input); check_span( r#"read=(int)5"#, is_node.get("read").unwrap().span(), &input, ); check_span(r#"10.1"#, is_node.get(1).unwrap().span(), &input); check_span(r#"(u32)0x45"#, is_node.get(2).unwrap().span(), &input); // Now let's look at some messed up parts of that "and" node let and_node = doc .get("this") .unwrap() .children() .unwrap() .get("and") .unwrap(); // The node is what you expect, the whole line and its two braces check_span( r####"and x="" { "it" /*shh*/ "has"="💯" r##"the"## Best🎊est "syntax ever" }"####, and_node.span(), &input, ); // The child document is a little weird, it's the contents *inside* the braces // with extra newlines on both ends. check_span( r####" "it" /*shh*/ "has"="💯" r##"the"## Best🎊est "syntax ever" "####, and_node.children().unwrap().span(), &input, ); // Oh hey don't forget to check that "x" entry check_span(r#"x="""#, and_node.get("x").unwrap().span(), &input); // Now the "it" node, more straightforward let it_node = and_node.children().unwrap().get("it").unwrap(); check_span( r####""it" /*shh*/ "has"="💯" r##"the"##"####, it_node.span(), &input, ); check_span(r#""has"="💯""#, it_node.get("has").unwrap().span(), &input); check_span( r####"r##"the"##"####, it_node.get(0).unwrap().span(), &input, ); // Make sure inline nodes work ok let inline_node = doc.get("inline").unwrap(); check_span( r#"inline { time; to; live "our" "dreams"; "y;all"; }"#, inline_node.span(), &input, ); let inline_children = inline_node.children().unwrap(); check_span( r#" time; to; live "our" "dreams"; "y;all"; "#, inline_children.span(), &input, ); let inline_nodes = inline_children.nodes(); check_span("time", inline_nodes[0].span(), &input); check_span("to", inline_nodes[1].span(), &input); check_span(r#"live "our" "dreams""#, inline_nodes[2].span(), &input); check_span(r#""y;all""#, inline_nodes[3].span(), &input); Ok(()) } #[test] fn parse_examples() -> miette::Result<()> { include_str!("../examples/kdl-schema.kdl").parse::()?; include_str!("../examples/Cargo.kdl").parse::()?; include_str!("../examples/ci.kdl").parse::()?; include_str!("../examples/nuget.kdl").parse::()?; Ok(()) } } kdl-4.6.0/src/entry.rs000064400000000000000000000225070072674642500127410ustar 00000000000000#[cfg(feature = "span")] use miette::SourceSpan; use std::{fmt::Display, str::FromStr}; use crate::{parser, KdlError, KdlIdentifier, KdlValue}; /// KDL Entries are the "arguments" to KDL nodes: either a (positional) /// [`Argument`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#argument) or /// a (key/value) /// [`Property`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#property) #[derive(Debug, Clone)] pub struct KdlEntry { pub(crate) leading: Option, pub(crate) ty: Option, pub(crate) value: KdlValue, pub(crate) value_repr: Option, pub(crate) name: Option, pub(crate) trailing: Option, #[cfg(feature = "span")] pub(crate) span: SourceSpan, } impl PartialEq for KdlEntry { fn eq(&self, other: &Self) -> bool { self.leading == other.leading && self.ty == other.ty && self.value == other.value && self.value_repr == other.value_repr && self.name == other.name && self.trailing == other.trailing // intentionally omitted: self.span == other.span } } impl KdlEntry { /// Creates a new Argument (positional) KdlEntry. pub fn new(value: impl Into) -> Self { KdlEntry { leading: None, ty: None, value: value.into(), value_repr: None, name: None, trailing: None, #[cfg(feature = "span")] span: SourceSpan::from(0..0), } } /// Gets a reference to this entry's name, if it's a property entry. pub fn name(&self) -> Option<&KdlIdentifier> { self.name.as_ref() } /// Gets the entry's value. pub fn value(&self) -> &KdlValue { &self.value } /// Gets a mutable reference to this entry's value. pub fn value_mut(&mut self) -> &mut KdlValue { &mut self.value } /// Sets the entry's value. pub fn set_value(&mut self, value: impl Into) { self.value = value.into(); } /// Gets this entry's span. /// /// This value will be properly initialized when created via [`KdlDocument::parse`] /// but may become invalidated if the document is mutated. We do not currently /// guarantee this to yield any particularly consistent results at that point. #[cfg(feature = "span")] pub fn span(&self) -> &SourceSpan { &self.span } /// Gets a mutable reference to this entry's span. #[cfg(feature = "span")] pub fn span_mut(&mut self) -> &mut SourceSpan { &mut self.span } /// Sets this entry's span. #[cfg(feature = "span")] pub fn set_span(&mut self, span: impl Into) { self.span = span.into(); } /// Gets the entry's type. pub fn ty(&self) -> Option<&KdlIdentifier> { self.ty.as_ref() } /// Gets a mutable reference to this entry's type. pub fn ty_mut(&mut self) -> Option<&mut KdlIdentifier> { self.ty.as_mut() } /// Sets the entry's type. pub fn set_ty(&mut self, ty: impl Into) { self.ty = Some(ty.into()); } /// Creates a new Property (key/value) KdlEntry. pub fn new_prop(key: impl Into, value: impl Into) -> Self { KdlEntry { leading: None, ty: None, value: value.into(), value_repr: None, name: Some(key.into()), trailing: None, #[cfg(feature = "span")] span: SourceSpan::from(0..0), } } /// Gets leading text (whitespace, comments) for this KdlEntry. pub fn leading(&self) -> Option<&str> { self.leading.as_deref() } /// Sets leading text (whitespace, comments) for this KdlEntry. pub fn set_leading(&mut self, leading: impl Into) { self.leading = Some(leading.into()); } /// Gets trailing text (whitespace, comments) for this KdlEntry. pub fn trailing(&self) -> Option<&str> { self.trailing.as_deref() } /// Sets trailing text (whitespace, comments) for this KdlEntry. pub fn set_trailing(&mut self, trailing: impl Into) { self.trailing = Some(trailing.into()); } /// Clears leading and trailing text (whitespace, comments), as well as /// resetting this entry's value to its default representation. pub fn clear_fmt(&mut self) { self.leading = None; self.trailing = None; self.value_repr = None; if let Some(ty) = &mut self.ty { ty.clear_fmt(); } if let Some(name) = &mut self.name { name.clear_fmt(); } } /// Gets the custom string representation for this KdlEntry's [`KdlValue`]. pub fn value_repr(&self) -> Option<&str> { self.value_repr.as_deref() } /// Sets a custom string representation for this KdlEntry's [`KdlValue`]. pub fn set_value_repr(&mut self, repr: impl Into) { self.value_repr = Some(repr.into()); } /// Length of this entry when rendered as a string. pub fn len(&self) -> usize { format!("{}", self).len() } /// Returns true if this entry is completely empty (including whitespace). pub fn is_empty(&self) -> bool { self.len() == 0 } /// Auto-formats this entry. pub fn fmt(&mut self) { self.leading = None; self.trailing = None; self.value_repr = None; if let Some(name) = &mut self.name { name.fmt(); } } } impl Display for KdlEntry { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(leading) = &self.leading { write!(f, "{}", leading)?; } if let Some(name) = &self.name { write!(f, "{}=", name)?; } if let Some(ty) = &self.ty { write!(f, "({})", ty)?; } if let Some(repr) = &self.value_repr { write!(f, "{}", repr)?; } else { write!(f, "{}", self.value)?; } if let Some(trailing) = &self.trailing { write!(f, "{}", trailing)?; } Ok(()) } } impl From for KdlEntry where T: Into, { fn from(value: T) -> Self { KdlEntry::new(value) } } impl From<(K, V)> for KdlEntry where K: Into, V: Into, { fn from((key, value): (K, V)) -> Self { KdlEntry::new_prop(key, value) } } impl FromStr for KdlEntry { type Err = KdlError; fn from_str(s: &str) -> Result { let kdl_parser = parser::KdlParser::new(s); kdl_parser.parse(parser::entry_with_trailing(&kdl_parser)) } } #[cfg(test)] mod test { use super::*; #[test] fn reset_value_repr() -> miette::Result<()> { let mut left_entry: KdlEntry = " name=1.03e2".parse()?; let mut right_entry: KdlEntry = " name=103.0".parse()?; assert_ne!(left_entry, right_entry); left_entry.clear_fmt(); right_entry.clear_fmt(); assert_eq!(left_entry, right_entry); Ok(()) } #[test] fn new() { let entry = KdlEntry::new(42); assert_eq!( entry, KdlEntry { leading: None, ty: None, value: KdlValue::Base10(42), value_repr: None, name: None, trailing: None, #[cfg(feature = "span")] span: SourceSpan::from(0..0), } ); let entry = KdlEntry::new_prop("name", 42); assert_eq!( entry, KdlEntry { leading: None, ty: None, value: KdlValue::Base10(42), value_repr: None, name: Some("name".into()), trailing: None, #[cfg(feature = "span")] span: SourceSpan::from(0..0), } ); } #[test] fn parsing() -> miette::Result<()> { let entry: KdlEntry = " \\\n (\"m\\\"eh\")0xDEADbeef\t\\\n".parse()?; assert_eq!( entry, KdlEntry { leading: Some(" \\\n ".into()), ty: Some("\"m\\\"eh\"".parse()?), value: KdlValue::Base16(0xdeadbeef), value_repr: Some("0xDEADbeef".into()), name: None, trailing: Some("\t\\\n".into()), #[cfg(feature = "span")] span: SourceSpan::from(0..0), } ); let entry: KdlEntry = " \\\n \"foo\"=(\"m\\\"eh\")0xDEADbeef\t\\\n".parse()?; assert_eq!( entry, KdlEntry { leading: Some(" \\\n ".into()), ty: Some("\"m\\\"eh\"".parse()?), value: KdlValue::Base16(0xdeadbeef), value_repr: Some("0xDEADbeef".into()), name: Some("\"foo\"".parse()?), trailing: Some("\t\\\n".into()), #[cfg(feature = "span")] span: SourceSpan::from(0..0), } ); Ok(()) } #[test] fn display() { let entry = KdlEntry::new(KdlValue::Base10(42)); assert_eq!(format!("{}", entry), "42"); let entry = KdlEntry::new_prop("name", KdlValue::Base10(42)); assert_eq!(format!("{}", entry), "name=42"); } } kdl-4.6.0/src/error.rs000064400000000000000000000102720072674642500127250ustar 00000000000000use std::num::{ParseFloatError, ParseIntError}; use miette::{Diagnostic, SourceSpan}; use nom::error::{ContextError, ErrorKind, FromExternalError, ParseError}; use thiserror::Error; #[cfg(doc)] use { crate::KdlNode, std::convert::{TryFrom, TryInto}, }; /// An error that occurs when parsing a KDL document. /// /// This error implements [`miette::Diagnostic`] and can be used to display /// detailed, pretty-printed diagnostic messages when using [`miette::Result`] /// and the `"fancy"` feature flag for `miette`: /// /// ```no_run /// fn main() -> miette::Result<()> { /// "foo 1.".parse::()?; /// Ok(()) /// } /// ``` /// /// This will display a message like: /// ```text /// Error: /// × Expected valid value. /// ╭──── /// 1 │ foo 1. /// · ─┬ /// · ╰── invalid float /// ╰──── /// help: Floating point numbers must be base 10, and have numbers after the decimal point. /// ``` #[derive(Debug, Diagnostic, Clone, Eq, PartialEq, Error)] #[error("{kind}")] pub struct KdlError { /// Source string for the KDL document that failed to parse. #[source_code] pub input: String, /// Offset in chars of the error. #[label("{}", label.unwrap_or("here"))] pub span: SourceSpan, /// Label text for this span. Defaults to `"here"`. pub label: Option<&'static str>, /// Suggestion for fixing the parser error. #[help] pub help: Option<&'static str>, /// Specific error kind for this parser error. pub kind: KdlErrorKind, } /// A type reprenting additional information specific to the type of error being returned. #[derive(Debug, Diagnostic, Clone, Eq, PartialEq, Error)] pub enum KdlErrorKind { /// An error occurred while parsing an integer. #[error(transparent)] #[diagnostic(code(kdl::parse_int))] ParseIntError(ParseIntError), /// An error occurred while parsing a floating point number. #[error(transparent)] #[diagnostic(code(kdl::parse_float))] ParseFloatError(ParseFloatError), /// Generic parsing error. The given context string denotes the component /// that failed to parse. #[error("Expected {0}.")] #[diagnostic(code(kdl::parse_component))] Context(&'static str), /// Generic unspecified error. If this is returned, the call site should /// be annotated with context, if possible. #[error("An unspecified error occurred.")] #[diagnostic(code(kdl::other))] Other, } #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) struct KdlParseError { pub(crate) input: I, pub(crate) context: Option<&'static str>, pub(crate) len: usize, pub(crate) label: Option<&'static str>, pub(crate) help: Option<&'static str>, pub(crate) kind: Option, pub(crate) touched: bool, } impl ParseError for KdlParseError { fn from_error_kind(input: I, _kind: nom::error::ErrorKind) -> Self { Self { input, len: 0, label: None, help: None, context: None, kind: None, touched: false, } } fn append(_input: I, _kind: nom::error::ErrorKind, other: Self) -> Self { other } } impl ContextError for KdlParseError { fn add_context(_input: I, ctx: &'static str, mut other: Self) -> Self { other.context = other.context.or(Some(ctx)); other } } impl<'a> FromExternalError<&'a str, ParseIntError> for KdlParseError<&'a str> { fn from_external_error(input: &'a str, _kind: ErrorKind, e: ParseIntError) -> Self { KdlParseError { input, len: 0, label: None, help: None, context: None, kind: Some(KdlErrorKind::ParseIntError(e)), touched: false, } } } impl<'a> FromExternalError<&'a str, ParseFloatError> for KdlParseError<&'a str> { fn from_external_error(input: &'a str, _kind: ErrorKind, e: ParseFloatError) -> Self { KdlParseError { input, len: 0, label: None, help: None, context: None, kind: Some(KdlErrorKind::ParseFloatError(e)), touched: false, } } } kdl-4.6.0/src/fmt.rs000064400000000000000000000025200072674642500123570ustar 00000000000000use std::fmt::Write as _; pub(crate) fn fmt_leading(leading: &mut String, indent: usize, no_comments: bool) { if leading.is_empty() { return; } let mut result = String::new(); if !no_comments { let input = leading.trim(); let kdl_parser = crate::parser::KdlParser { full_input: input }; let comments = kdl_parser .parse(crate::parser::leading_comments(&kdl_parser)) .expect("invalid leading text"); for line in comments { let trimmed = line.trim(); if !trimmed.is_empty() { writeln!(result, "{:indent$}{}", "", trimmed, indent = indent).unwrap(); } } } write!(result, "{:indent$}", "", indent = indent).unwrap(); *leading = result; } pub(crate) fn fmt_trailing(decor: &mut String, no_comments: bool) { if decor.is_empty() { return; } *decor = decor.trim().to_string(); let mut result = String::new(); if !no_comments { let input = &*decor; let kdl_parser = crate::parser::KdlParser { full_input: input }; let comments = kdl_parser .parse(crate::parser::trailing_comments(&kdl_parser)) .expect("invalid trailing text"); for comment in comments { result.push_str(comment); } } *decor = result; } kdl-4.6.0/src/identifier.rs000064400000000000000000000163770072674642500137320ustar 00000000000000#[cfg(feature = "span")] use miette::SourceSpan; use std::{fmt::Display, str::FromStr}; use crate::{parser, KdlError}; /// Represents a KDL /// [Identifier](https://github.com/kdl-org/kdl/blob/main/SPEC.md#identifier). #[derive(Debug, Clone, Eq)] pub struct KdlIdentifier { pub(crate) value: String, pub(crate) repr: Option, #[cfg(feature = "span")] pub(crate) span: SourceSpan, } impl PartialEq for KdlIdentifier { fn eq(&self, other: &Self) -> bool { self.value == other.value && self.repr == other.repr // intentionally omitted: self.span == other.span } } impl std::hash::Hash for KdlIdentifier { fn hash(&self, state: &mut H) { self.value.hash(state); self.repr.hash(state); // Intentionally omitted: self.span.hash(state); } } impl KdlIdentifier { /// Gets the string value for this identifier. pub fn value(&self) -> &str { &self.value } /// Sets the string value for this identifier. pub fn set_value(&mut self, value: impl Into) { self.value = value.into(); } /// Gets this identifier's span. /// /// This value will be properly initialized when created via [`KdlDocument::parse`] /// but may become invalidated if the document is mutated. We do not currently /// guarantee this to yield any particularly consistent results at that point. #[cfg(feature = "span")] pub fn span(&self) -> &SourceSpan { &self.span } /// Gets a mutable reference to this identifier's span. #[cfg(feature = "span")] pub fn span_mut(&mut self) -> &mut SourceSpan { &mut self.span } /// Sets this identifier's span. #[cfg(feature = "span")] pub fn set_span(&mut self, span: impl Into) { self.span = span.into(); } /// Gets the custom string representation for this identifier, if any. pub fn repr(&self) -> Option<&str> { self.repr.as_deref() } /// Sets a custom string representation for this identifier. pub fn set_repr(&mut self, repr: impl Into) { self.repr = Some(repr.into()); } /// Length of this identifier when rendered as a string. pub fn len(&self) -> usize { format!("{}", self).len() } /// Returns true if this identifier is completely empty. pub fn is_empty(&self) -> bool { self.len() == 0 } /// Resets this identifier to its default representation. It will attempt /// to make it an unquoted identifier, and fall back to a string /// representation if that would be invalid. pub fn clear_fmt(&mut self) { self.repr = None; } /// Auto-formats this identifier. pub fn fmt(&mut self) { self.repr = None; } } impl Display for KdlIdentifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(repr) = &self.repr { write!(f, "{}", repr) } else if self.plain_value() { write!(f, "{}", self.value) } else { write!(f, "{:?}", self.value) } } } impl KdlIdentifier { pub(crate) fn is_identifier_char(c: char) -> bool { !((c as u32) < 0x20 || (c as u32) > 0x10ffff || matches!( c, '\\' | '/' | '(' | ')' | '{' | '}' | '<' | '>' | ';' | '[' | ']' | '=' | ',' | '"' // Newlines | '\r' | '\n' | '\u{0085}' | '\u{000C}' | '\u{2028}' | '\u{2029}' // Whitespace | ' ' | '\t' | '\u{FEFF}' | '\u{00A0}' | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}' | '\u{2005}' | '\u{2006}' | '\u{2007}' | '\u{2008}' | '\u{2009}' | '\u{200A}' | '\u{202F}' | '\u{205F}' | '\u{3000}' )) } pub(crate) fn is_initial_char(c: char) -> bool { !c.is_numeric() && Self::is_identifier_char(c) } fn plain_value(&self) -> bool { let mut iter = self.value.chars(); if let Some(c) = iter.next() { if !Self::is_initial_char(c) { return false; } } else { return false; } for char in iter { if !Self::is_identifier_char(char) { return false; } } true } } impl From<&str> for KdlIdentifier { fn from(value: &str) -> Self { KdlIdentifier { value: value.to_string(), repr: None, #[cfg(feature = "span")] span: SourceSpan::from(0..0), } } } impl From for KdlIdentifier { fn from(value: String) -> Self { KdlIdentifier { value, repr: None, #[cfg(feature = "span")] span: SourceSpan::from(0..0), } } } impl From for String { fn from(value: KdlIdentifier) -> Self { value.value } } impl FromStr for KdlIdentifier { type Err = KdlError; fn from_str(s: &str) -> Result { let kdl_parser = crate::parser::KdlParser::new(s); kdl_parser.parse(parser::identifier(&kdl_parser)) } } #[cfg(test)] mod test { use super::*; #[test] fn parsing() -> miette::Result<()> { let plain = "foo"; assert_eq!( plain.parse::()?, KdlIdentifier { value: plain.to_string(), repr: Some(plain.to_string()), #[cfg(feature = "span")] span: SourceSpan::from(0..3), } ); let quoted = "\"foo\\\"bar\""; assert_eq!( quoted.parse::()?, KdlIdentifier { value: "foo\"bar".to_string(), repr: Some(quoted.to_string()), #[cfg(feature = "span")] span: SourceSpan::from(0..0), } ); let invalid = "123"; assert!(invalid.parse::().is_err()); let invalid = " space "; assert!(invalid.parse::().is_err()); let invalid = "\"x"; assert!(invalid.parse::().is_err()); Ok(()) } #[test] fn formatting() { let plain = KdlIdentifier::from("foo"); assert_eq!(format!("{}", plain), "foo"); let quoted = KdlIdentifier::from("foo\"bar"); assert_eq!(format!("{}", quoted), r#""foo\"bar""#); let mut custom_repr = KdlIdentifier::from("foo"); custom_repr.set_repr(r#""foo/bar""#.to_string()); assert_eq!(format!("{}", custom_repr), r#""foo/bar""#); } } kdl-4.6.0/src/lib.rs000064400000000000000000000105370072674642500123460ustar 00000000000000//! `kdl` is a "document-oriented" parser and API for the [KDL Document //! Language](https://kdl.dev), a node-based, human-friendly configuration and //! serialization format. Unlike serde-based implementations, this crate //! preserves formatting when editing, as well as when inserting or changing //! values with custom formatting. This is most useful when working with //! human-maintained KDL files. //! //! You can think of this crate as //! [`toml_edit`](https://crates.io/crates/toml_edit), but for KDL. //! //! If you don't care about formatting or programmatic manipulation, you might //! check out [`knuffel`](https://crates.io/crates/knuffel) or //! [`kaydle`](https://crates.io/crates/kaydle) instead for serde (or //! serde-like) parsing. //! //! ## Example //! //! ```rust //! use kdl::KdlDocument; //! //! let doc_str = r#" //! hello 1 2 3 //! //! world prop="value" { //! child 1 //! child 2 //! } //! "#; //! //! let doc: KdlDocument = doc_str.parse().expect("failed to parse KDL"); //! //! assert_eq!( //! doc.get_args("hello"), //! vec![&1.into(), &2.into(), &3.into()] //! ); //! //! assert_eq!( //! doc.get("world").map(|node| &node["prop"]), //! Some(&"value".into()) //! ); //! //! // Documents fully roundtrip: //! assert_eq!(doc.to_string(), doc_str); //! ``` //! //! ## Controlling Formatting //! //! By default, everything is created with default formatting. You can parse //! items manually to provide custom representations, comments, etc: //! //! ```rust //! let node_str = r#" //! // indented comment //! "formatted" 1 /* comment */ \ //! 2; //! "#; //! //! let mut doc = kdl::KdlDocument::new(); //! doc.nodes_mut().push(node_str.parse().unwrap()); //! //! assert_eq!(&doc.to_string(), node_str); //! ``` //! //! [`KdlDocument`], [`KdlNode`], [`KdlEntry`], and [`KdlIdentifier`] can all //! be parsed and managed this way. //! //! ## Error Reporting //! //! [`KdlError`] implements [`miette::Diagnostic`] and can be used to display //! detailed, pretty-printed diagnostic messages when using [`miette::Result`] //! and the `"fancy"` feature flag for `miette`: //! //! ```toml //! # Cargo.toml //! [dependencies] //! miette = { version = "x.y.z", features = ["fancy"] } //! ``` //! //! ```no_run //! fn main() -> miette::Result<()> { //! "foo 1.".parse::()?; //! Ok(()) //! } //! ``` //! //! This will display a message like: //! ```text //! Error: //! × Expected valid value. //! ╭──── //! 1 │ foo 1. //! · ─┬ //! · ╰── invalid float //! ╰──── //! help: Floating point numbers must be base 10, and have numbers after the decimal point. //! ``` //! //! ## Quirks //! //! ### Properties //! //! Multiple properties with the same name are allowed, and all duplicated //! **will be preserved**, meaning those documents will correctly round-trip. //! When using `node.get()`/`node["key"]` & company, the _last_ property with //! that name's value will be returned. //! //! ### Numbers //! //! KDL itself does not specify a particular representation for numbers and //! accepts just about anything valid, no matter how large and how small. This //! means a few things: //! //! * Numbers without a decimal point are interpreted as [`u64`]. //! * Numbers with a decimal point are interpreted as [`f64`]. //! * Floating point numbers that evaluate to [`f64::INFINITY`] or //! [`f64::NEG_INFINITY`] or NaN will be represented as such in the values, //! instead of the original numbers. //! * A similar restriction applies to overflowed [`u64`] values. //! * The original _representation_ of these numbers will be preserved, unless //! you [`KdlDocument::fmt`] in which case the original representation will be //! thrown away and the actual value will be used when serializing. //! //! ## License //! //! The code in this repository is covered by [the Apache-2.0 //! License](LICENSE.md). #![deny(missing_debug_implementations, nonstandard_style)] #![warn(missing_docs, unreachable_pub, rust_2018_idioms, unreachable_pub)] #![cfg_attr(test, deny(warnings))] #![doc(html_favicon_url = "https://kdl.dev/favicon.ico")] #![doc(html_logo_url = "https://kdl.dev/logo.svg")] pub use document::*; pub use entry::*; pub use error::*; pub use identifier::*; pub use node::*; pub use value::*; mod document; mod entry; mod error; mod fmt; mod identifier; mod node; mod nom_compat; mod parser; mod value; kdl-4.6.0/src/node.rs000064400000000000000000000465260072674642500125340ustar 00000000000000use std::{ fmt::Display, ops::{Index, IndexMut}, str::FromStr, }; #[cfg(feature = "span")] use miette::SourceSpan; use crate::{parser, KdlDocument, KdlEntry, KdlError, KdlIdentifier, KdlValue}; /// Represents an individual KDL /// [`Node`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node) inside a /// KDL Document. #[derive(Debug, Clone)] pub struct KdlNode { pub(crate) leading: Option, pub(crate) ty: Option, pub(crate) name: KdlIdentifier, // TODO: consider using `hashlink` for this instead, later. pub(crate) entries: Vec, pub(crate) before_children: Option, pub(crate) children: Option, pub(crate) trailing: Option, #[cfg(feature = "span")] pub(crate) span: SourceSpan, } impl PartialEq for KdlNode { fn eq(&self, other: &Self) -> bool { self.leading == other.leading && self.ty == other.ty && self.name == other.name && self.entries == other.entries && self.before_children == other.before_children && self.children == other.children && self.trailing == other.trailing // intentionally omitted: self.span == other.span } } impl KdlNode { /// Creates a new KdlNode with a given name. pub fn new(name: impl Into) -> Self { Self { name: name.into(), leading: None, ty: None, entries: Vec::new(), before_children: None, children: None, trailing: None, #[cfg(feature = "span")] span: SourceSpan::from(0..0), } } /// Gets this node's name. pub fn name(&self) -> &KdlIdentifier { &self.name } /// Gets a mutable reference to this node's name. pub fn name_mut(&mut self) -> &mut KdlIdentifier { &mut self.name } /// Sets this node's name. pub fn set_name(&mut self, name: impl Into) { self.name = name.into(); } /// Gets this node's span. /// /// This value will be properly initialized when created via [`KdlDocument::parse`] /// but may become invalidated if the document is mutated. We do not currently /// guarantee this to yield any particularly consistent results at that point. #[cfg(feature = "span")] pub fn span(&self) -> &SourceSpan { &self.span } /// Gets a mutable reference to this node's span. #[cfg(feature = "span")] pub fn span_mut(&mut self) -> &mut SourceSpan { &mut self.span } /// Sets this node's span. #[cfg(feature = "span")] pub fn set_span(&mut self, span: impl Into) { self.span = span.into(); } /// Gets the node's type identifier, if any. pub fn ty(&self) -> Option<&KdlIdentifier> { self.ty.as_ref() } /// Gets a mutable reference to the node's type identifier. pub fn ty_mut(&mut self) -> &mut Option { &mut self.ty } /// Sets the node's type identifier. pub fn set_ty(&mut self, ty: impl Into) { self.ty = Some(ty.into()); } /// Returns a reference to this node's entries (arguments and properties). pub fn entries(&self) -> &[KdlEntry] { &self.entries } /// Returns a mutable reference to this node's entries (arguments and /// properties). pub fn entries_mut(&mut self) -> &mut Vec { &mut self.entries } /// Gets leading text (whitespace, comments) for this node. pub fn leading(&self) -> Option<&str> { self.leading.as_deref() } /// Sets leading text (whitespace, comments) for this node. pub fn set_leading(&mut self, leading: impl Into) { self.leading = Some(leading.into()); } /// Gets text (whitespace, comments) right before the children block's starting `{`. pub fn before_children(&self) -> Option<&str> { self.before_children.as_deref() } /// Gets text (whitespace, comments) right before the children block's starting `{`. pub fn set_before_children(&mut self, before: impl Into) { self.before_children = Some(before.into()); } /// Gets trailing text (whitespace, comments) for this node. pub fn trailing(&self) -> Option<&str> { self.trailing.as_deref() } /// Sets trailing text (whitespace, comments) for this node. pub fn set_trailing(&mut self, trailing: impl Into) { self.trailing = Some(trailing.into()); } /// Length of this node when rendered as a string. pub fn len(&self) -> usize { format!("{}", self).len() } /// Returns true if this node is completely empty (including whitespace). pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears leading and trailing text (whitespace, comments), as well as /// the space before the children block, if any. Individual entries and /// their formatting will be preserved. /// /// If you want to clear formatting on all children and entries as well, /// use [`Self::clear_fmt_recursive`]. pub fn clear_fmt(&mut self) { self.leading = None; self.trailing = None; self.before_children = None; } /// Clears leading and trailing text (whitespace, comments), as well as /// the space before the children block, if any. Individual entries and /// children formatting will also be cleared. pub fn clear_fmt_recursive(&mut self) { self.clear_fmt(); self.name.clear_fmt(); if let Some(children) = &mut self.children { children.clear_fmt_recursive(); } for entry in self.entries.iter_mut() { entry.clear_fmt(); } } /// Fetches an entry by key. Number keys will look up arguments, strings /// will look up properties. pub fn get(&self, key: impl Into) -> Option<&KdlEntry> { self.get_impl(key.into()) } fn get_impl(&self, key: NodeKey) -> Option<&KdlEntry> { match key { NodeKey::Key(key) => { let mut current = None; for entry in &self.entries { if entry.name.is_some() && entry.name.as_ref().map(|i| i.value()) == Some(key.value()) { current = Some(entry); } } current } NodeKey::Index(idx) => { let mut current_idx = 0; for entry in &self.entries { if entry.name.is_none() { if current_idx == idx { return Some(entry); } current_idx += 1; if current_idx > idx + 1 { return None; } } } None } } } /// Fetches a mutable referene to an entry by key. Number keys will look /// up arguments, strings will look up properties. pub fn get_mut(&mut self, key: impl Into) -> Option<&mut KdlEntry> { self.get_mut_impl(key.into()) } fn get_mut_impl(&mut self, key: NodeKey) -> Option<&mut KdlEntry> { match key { NodeKey::Key(key) => { let mut current = None; for entry in &mut self.entries { if entry.name.is_some() && entry.name.as_ref().map(|i| i.value()) == Some(key.value()) { current = Some(entry); } } current } NodeKey::Index(idx) => { let mut current_idx = 0; for entry in &mut self.entries { if entry.name.is_none() { if current_idx >= idx { return Some(entry); } current_idx += 1; if current_idx >= idx { return None; } } } None } } } /// Inserts an entry into this node. If an entry already exists with the /// same key, it will be replaced and the previous entry will be returned. /// /// Numerical keys will insert arguments, string keys will insert /// properties. pub fn insert( &mut self, key: impl Into, entry: impl Into, ) -> Option { self.insert_impl(key.into(), entry.into()) } fn insert_impl(&mut self, key: NodeKey, mut entry: KdlEntry) -> Option { match key { NodeKey::Key(ref key_val) => { if entry.name.is_none() { entry.name = Some(key_val.clone()); } if entry.name.as_ref().map(|i| i.value()) != Some(key_val.value()) { panic!("Property name mismatch"); } if let Some(existing) = self.get_mut(key) { std::mem::swap(existing, &mut entry); Some(entry) } else { self.entries.push(entry); None } } NodeKey::Index(idx) => { if entry.name.is_some() { panic!("Cannot insert property with name under a numerical key"); } if let Some(existing) = self.get_mut(key) { std::mem::swap(existing, &mut entry); Some(entry) } else { let mut current_idx = 0; for existing in &mut self.entries { if existing.name.is_none() { if current_idx == idx { std::mem::swap(existing, &mut entry); return Some(entry); } current_idx += 1; if current_idx >= idx { break; } } } if idx > current_idx { panic!( "Insertion index (is {}) should be <= len (is {})", idx, current_idx ); } else { self.entries.push(entry); None } } } } } /// Removes an entry from this node. If an entry already exists with the /// same key, it will be returned. /// /// Numerical keys will remove arguments, string keys will remove /// properties. pub fn remove(&mut self, key: impl Into) -> Option { self.remove_impl(key.into()) } fn remove_impl(&mut self, key: NodeKey) -> Option { match key { NodeKey::Key(key) => { for (idx, entry) in self.entries.iter_mut().enumerate() { if entry.name.is_some() && entry.name.as_ref() == Some(&key) { return Some(self.entries.remove(idx)); } } None } NodeKey::Index(idx) => { let mut current_idx = 0; for entry in &mut self.entries { if entry.name.is_none() { if current_idx == idx { return Some(self.entries.remove(idx)); } current_idx += 1; if current_idx >= idx { return None; } } } None } } } /// Shorthand for `self.entries_mut().push(entry)`. pub fn push(&mut self, entry: impl Into) { self.entries.push(entry.into()); } /// Shorthand for `self.entries_mut().clear()` pub fn clear_entries(&mut self) { self.entries.clear(); } /// Returns a reference to this node's children, if any. pub fn children(&self) -> Option<&KdlDocument> { self.children.as_ref() } /// Returns a mutable reference to this node's children, if any. pub fn children_mut(&mut self) -> &mut Option { &mut self.children } /// Sets the KdlDocument representing this node's children. pub fn set_children(&mut self, children: KdlDocument) { self.children = Some(children); } /// Removes this node's children completely. pub fn clear_children(&mut self) { self.children = None; } /// Returns a mutable reference to this node's children [`KdlDocument`], /// creating one first if one does not already exist. pub fn ensure_children(&mut self) -> &mut KdlDocument { if self.children.is_none() { self.children = Some(KdlDocument::new()); } self.children_mut().as_mut().unwrap() } /// Auto-formats this node and its contents. pub fn fmt(&mut self) { self.fmt_impl(0, false); } /// Auto-formats this node and its contents, stripping comments. pub fn fmt_no_comments(&mut self) { self.fmt_impl(0, true); } } /// Represents a [`KdlNode`]'s entry key. #[derive(Debug, Clone, PartialEq, Eq)] pub enum NodeKey { /// Key for a node property entry. Key(KdlIdentifier), /// Index for a node argument entry (positional value). Index(usize), } impl From<&str> for NodeKey { fn from(key: &str) -> Self { NodeKey::Key(key.into()) } } impl From for NodeKey { fn from(key: String) -> Self { NodeKey::Key(key.into()) } } impl From for NodeKey { fn from(key: usize) -> Self { NodeKey::Index(key) } } impl Index for KdlNode { type Output = KdlValue; fn index(&self, index: usize) -> &Self::Output { self.get(index).expect("Argument out of range.").value() } } impl IndexMut for KdlNode { fn index_mut(&mut self, index: usize) -> &mut Self::Output { self.get_mut(index) .expect("Argument out of range.") .value_mut() } } impl Index<&str> for KdlNode { type Output = KdlValue; fn index(&self, key: &str) -> &Self::Output { self.get(key).expect("No such property.").value() } } impl IndexMut<&str> for KdlNode { fn index_mut(&mut self, key: &str) -> &mut Self::Output { if self.get(key).is_none() { self.push((key, KdlValue::Null)); } self.get_mut(key) .expect("Something went wrong.") .value_mut() } } impl FromStr for KdlNode { type Err = KdlError; fn from_str(input: &str) -> Result { let kdl_parser = crate::parser::KdlParser::new(input); kdl_parser.parse(parser::node(&kdl_parser)) } } impl Display for KdlNode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.stringify(f, 0) } } impl KdlNode { pub(crate) fn fmt_impl(&mut self, indent: usize, no_comments: bool) { if let Some(s) = self.leading.as_mut() { crate::fmt::fmt_leading(s, indent, no_comments); } if let Some(s) = self.trailing.as_mut() { crate::fmt::fmt_trailing(s, no_comments); if s.starts_with(';') { s.remove(0); } if let Some(c) = s.chars().next() { if !c.is_whitespace() { s.insert(0, ' '); } } s.push('\n'); } self.before_children = None; self.name.clear_fmt(); if let Some(ty) = self.ty.as_mut() { ty.clear_fmt() } for entry in &mut self.entries { entry.fmt(); } if let Some(children) = self.children.as_mut() { children.fmt_impl(indent + 4, no_comments); if let Some(leading) = children.leading.as_mut() { leading.push('\n'); } if let Some(trailing) = children.trailing.as_mut() { trailing.push_str(format!("{:indent$}", "", indent = indent).as_str()); } } } pub(crate) fn stringify( &self, f: &mut std::fmt::Formatter<'_>, indent: usize, ) -> std::fmt::Result { if let Some(leading) = &self.leading { write!(f, "{}", leading)?; } else { write!(f, "{:indent$}", "", indent = indent)?; } if let Some(ty) = &self.ty { write!(f, "({})", ty)?; } write!(f, "{}", self.name)?; let mut space_before_children = true; for entry in &self.entries { if entry.leading.is_none() { write!(f, " ")?; } write!(f, "{}", entry)?; space_before_children = entry.trailing.is_none(); } if let Some(children) = &self.children { if let Some(before) = self.before_children() { write!(f, "{}", before)?; } else if space_before_children { write!(f, " ")?; } write!(f, "{{")?; if children.leading.is_none() { writeln!(f)?; } children.stringify(f, indent + 4)?; if children.trailing.is_none() { write!(f, "{:indent$}", "", indent = indent)?; } write!(f, "}}")?; } if let Some(trailing) = &self.trailing { write!(f, "{}", trailing)?; } Ok(()) } } #[cfg(test)] mod test { use super::*; #[test] fn canonical_clear_fmt() -> miette::Result<()> { let mut left_node: KdlNode = r#"node /-"commented" param_name=103.000 { // This is a nested node nested 1 2 3 }"# .parse()?; let mut right_node: KdlNode = "node param_name=103.0 { nested 1 2 3; }".parse()?; assert_ne!(left_node, right_node); left_node.clear_fmt_recursive(); right_node.clear_fmt_recursive(); assert_eq!(left_node, right_node); Ok(()) } #[test] fn parsing() -> miette::Result<()> { let node: KdlNode = "\n\t (\"ty\")\"node\" 0xDEADbeef;\n".parse()?; assert_eq!(node.leading(), Some("\n\t ")); assert_eq!(node.trailing(), Some(";\n")); assert_eq!(node.ty(), Some(&"\"ty\"".parse()?)); assert_eq!(node.name(), &"\"node\"".parse()?); assert_eq!(node.get(0), Some(&"0xDEADbeef".parse()?)); r#" node "test" { link "blah" anything="self" }"# .parse::()?; Ok(()) } #[test] fn indexing() { let mut node = KdlNode::new("foo"); node.push("bar"); node["foo"] = 1.into(); assert_eq!(node[0], "bar".into()); assert_eq!(node["foo"], 1.into()); node[0] = false.into(); node["foo"] = KdlValue::Null; assert_eq!(node[0], false.into()); assert_eq!(node["foo"], KdlValue::Null); node.entries_mut().push(KdlEntry::new_prop("x", 1)); node.entries_mut().push(KdlEntry::new_prop("x", 2)); assert_eq!(&node["x"], &2.into()) } } kdl-4.6.0/src/nom_compat.rs000064400000000000000000000057130072674642500137340ustar 00000000000000use nom::error::{ErrorKind, ParseError}; use nom::{Err, IResult, Parser}; pub(crate) fn many0(mut f: F) -> impl FnMut(I) -> IResult, E> where I: Clone + PartialEq, F: Parser, E: ParseError, { move |mut i: I| { let mut acc = Vec::with_capacity(4); loop { match f.parse(i.clone()) { Err(Err::Error(_)) => return Ok((i, acc)), Err(e) => return Err(e), Ok((i1, o)) => { if i1 == i { return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many0))); } i = i1; acc.push(o); } } } } } pub(crate) fn many1(mut f: F) -> impl FnMut(I) -> IResult, E> where I: Clone + PartialEq, F: Parser, E: ParseError, { move |mut i: I| match f.parse(i.clone()) { Err(Err::Error(err)) => Err(Err::Error(E::append(i, ErrorKind::Many1, err))), Err(e) => Err(e), Ok((i1, o)) => { let mut acc = Vec::with_capacity(4); acc.push(o); i = i1; loop { match f.parse(i.clone()) { Err(Err::Error(_)) => return Ok((i, acc)), Err(e) => return Err(e), Ok((i1, o)) => { if i1 == i { return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1))); } i = i1; acc.push(o); } } } } } } pub(crate) fn many_till( mut f: F, mut g: G, ) -> impl FnMut(I) -> IResult, P), E> where I: Clone + PartialEq, F: Parser, G: Parser, E: ParseError, { move |mut i: I| { let mut res = Vec::new(); loop { match g.parse(i.clone()) { Ok((i1, o)) => return Ok((i1, (res, o))), Err(Err::Error(_)) => { match f.parse(i.clone()) { Err(Err::Error(err)) => { return Err(Err::Error(E::append(i, ErrorKind::ManyTill, err))) } Err(e) => return Err(e), Ok((i1, o)) => { // loop trip must always consume (otherwise infinite loops) if i1 == i { return Err(Err::Error(E::from_error_kind( i1, ErrorKind::ManyTill, ))); } res.push(o); i = i1; } } } Err(e) => return Err(e), } } } } kdl-4.6.0/src/parser.rs000064400000000000000000001143760072674642500131020ustar 00000000000000// A bunch of random variables/functions become dead when you disable // span support and rather than turning the code into complete cfg // swiss-cheese, it's simpler to just hush the compiler about it #![cfg_attr(not(feature = "span"), allow(dead_code, unused_variables))] use std::ops::RangeTo; use crate::nom_compat::{many0, many1, many_till}; use miette::SourceSpan; use nom::branch::alt; use nom::bytes::complete::{tag, take_until, take_while, take_while_m_n}; use nom::character::complete::{anychar, char, none_of, one_of}; use nom::combinator::{all_consuming, cut, eof, map, map_opt, map_res, opt, peek, recognize}; use nom::error::{context, ParseError}; use nom::sequence::{delimited, preceded, terminated, tuple}; use nom::{Finish, IResult, Offset, Parser, Slice}; use crate::{ KdlDocument, KdlEntry, KdlError, KdlErrorKind, KdlIdentifier, KdlNode, KdlParseError, KdlValue, }; /// The parser for the entire input. /// /// All of our parsing subroutines want to hold onto some global information /// to generate things like spans, so instead of making them simple free /// functions, we wrap their bodies in closures that take in a kdl_parser. /// The free functions then becoming constructors that return those closures. /// This is basically the same idea behind nom combinators like many0 which /// take an input to configure the combinator and then return a function. pub(crate) struct KdlParser<'a> { pub(crate) full_input: &'a str, } impl<'a> KdlParser<'a> { pub(crate) fn new(full_input: &'a str) -> Self { Self { full_input } } pub(crate) fn parse(&self, parser: P) -> Result where P: Parser<&'a str, T, KdlParseError<&'a str>>, { all_consuming(parser)(self.full_input) .finish() .map(|(_, arg)| arg) .map_err(|e| { let span_substr = &e.input[..e.len]; KdlError { input: self.full_input.into(), span: self.span_from_substr(span_substr), help: e.help, label: e.label, kind: if let Some(kind) = e.kind { kind } else if let Some(ctx) = e.context { KdlErrorKind::Context(ctx) } else { KdlErrorKind::Other }, } }) } /// Creates a span for an item using two substrings of self.full_input: /// /// * before: the remainder of the input before parsing the item /// * after: the remainder input after parsing the item /// /// All we really care about are the addresses of the strings, the lengths don't matter fn span_from_before_and_after(&self, before: &str, after: &str) -> SourceSpan { let base_addr = self.full_input.as_ptr() as usize; let before_addr = before.as_ptr() as usize; let after_addr = after.as_ptr() as usize; assert!( before_addr >= base_addr, "tried to get the span of a non-substring!" ); assert!( after_addr >= before_addr, "subslices were in wrong order for spanning!" ); let start = before_addr - base_addr; let end = after_addr - base_addr; SourceSpan::from(start..end) } /// Creates a span for an item using a substring of self.full_input /// /// Note that substr must be a literal substring, as in it must be /// a pointer into the same string! fn span_from_substr(&self, substr: &str) -> SourceSpan { let base_addr = self.full_input.as_ptr() as usize; let substr_addr = substr.as_ptr() as usize; assert!( substr_addr >= base_addr, "tried to get the span of a non-substring!" ); let start = substr_addr - base_addr; let end = start + substr.len(); SourceSpan::from(start..end) } } fn set_details<'a>( mut err: nom::Err>, start: &'a str, label: Option<&'static str>, help: Option<&'static str>, ) -> nom::Err> { match &mut err { nom::Err::Error(e) | nom::Err::Failure(e) => { if !e.touched { e.len = start.offset(e.input); e.input = start; e.label = label; e.help = help; e.touched = true; } } _ => {} } err } pub(crate) fn document<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlDocument, KdlParseError<&'a str>> + 'b { move |input| { let start = input; let (input, nodes) = many0(node(kdl_parser))(input)?; let (input, trailing) = all_whitespace(kdl_parser)(input)?; let mut doc = KdlDocument::new(); doc.set_leading(""); doc.set_trailing(trailing); *doc.nodes_mut() = nodes; #[cfg(feature = "span")] doc.set_span(kdl_parser.span_from_before_and_after(start, trailing)); Ok((input, doc)) } } pub(crate) fn node<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlNode, KdlParseError<&'a str>> + 'b { |input| { let (input, leading) = all_whitespace(kdl_parser)(input)?; let start = input; let (input, ty) = opt(context( "valid node type annotation", annotation(kdl_parser), ))(input)?; let (input, name) = context("valid node name", identifier(kdl_parser))(input)?; let (input, entries) = many0(context("valid node entry", entry(kdl_parser)))(input)?; let (input, children) = opt(context("valid node children block", children(kdl_parser)))(input)?; let (input, trailing) = context( "valid node terminator", cut(recognize(preceded( many0(node_space(kdl_parser)), alt(( terminated(recognize(tag(";")), opt(alt((linespace, eof)))), alt((newline, single_line_comment, eof)), )), ))), )(input) .map_err(|e| { set_details( e, start, Some("parsed node"), Some("Nodes can only be terminated by `;` or a valid line ending."), ) })?; let mut node = KdlNode::new(name); node.set_leading(leading); node.set_trailing(trailing); #[cfg(feature = "span")] node.set_span(kdl_parser.span_from_before_and_after(start, trailing)); node.ty = ty; let ents = node.entries_mut(); *ents = entries; if let Some((before, children)) = children { let childs = node.children_mut(); *childs = Some(children); node.set_before_children(before); } Ok((input, node)) } } pub(crate) fn identifier<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlIdentifier, KdlParseError<&'a str>> + 'b { move |input| alt((quoted_identifier(kdl_parser), plain_identifier(kdl_parser)))(input) } pub(crate) fn leading_comments<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, Vec<&'a str>, KdlParseError<&'a str>> + 'b { move |input| { terminated( many0(preceded( opt(many0(alt((newline, unicode_space)))), comment(kdl_parser), )), opt(many0(alt((newline, unicode_space, eof)))), )(input) } } pub(crate) fn trailing_comments<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, Vec<&'a str>, KdlParseError<&'a str>> + 'b { move |mut input| { let mut comments = vec![]; loop { let (inp, _) = opt(many0(alt((newline, unicode_space, tag("\\")))))(input)?; let (inp, comment) = opt(comment(kdl_parser))(inp)?; if let Some(comment) = comment { comments.push(comment); } let (inp, _) = opt(many0(alt((newline, unicode_space, tag("\\"), tag(";")))))(inp)?; let (inp, end) = opt(eof)(inp)?; if end.is_some() { return Ok((inp, comments)); } if input == inp { panic!("invalid trailing text"); } input = inp; } } } /// A "fake" parser to provide better diagnostics when a bare identifier /// is used in places it shouldn't. fn errant_plain_identifier<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlEntry, KdlParseError<&'a str>> + 'b { move |input| { let start = input; let (_input, name) = plain_identifier(kdl_parser)(input)?; Err(nom::Err::Failure(KdlParseError { input: start, context: Some("a valid node entry"), len: name.len(), label: Some("plain identifiers can't be used here"), help: Some("If this was supposed to be a string, wrap it in quotes.\nIf this was supposed to be a new node, terminate the previous node with `;` or a newline."), kind: None, touched: false, })) } } fn plain_identifier<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlIdentifier, KdlParseError<&'a str>> + 'b { move |input| { let start = input; let (input, name) = recognize(preceded( take_while_m_n(1, 1, KdlIdentifier::is_initial_char), cut(take_while(KdlIdentifier::is_identifier_char)), ))(input).map_err(|e| set_details(e, start, Some("invalid identifier character"), Some("See https://github.com/kdl-org/kdl/blob/main/SPEC.md#identifier for an explanation of valid KDL identifiers.")))?; match name { "false" | "true" | "null" => { return Err(nom::Err::Error(KdlParseError { input, context: Some("non-keyword identifier"), len: name.len(), label: Some("reserved keyword"), help: Some("Reserved keywords cannot be used as identifiers."), kind: None, touched: false, })) } _ => {} } let mut ident = KdlIdentifier::from(name); ident.set_repr(name); #[cfg(feature = "span")] ident.set_span(kdl_parser.span_from_before_and_after(start, input)); Ok((input, ident)) } } fn quoted_identifier<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&str, KdlIdentifier, KdlParseError<&str>> + 'b { move |input| { let start = input; let (input, (raw, val)) = alt((string, raw_string))(input)?; let mut ident = KdlIdentifier::from(val.as_string().unwrap()); ident.set_repr(raw); #[cfg(feature = "span")] ident.set_span(kdl_parser.span_from_before_and_after(start, input)); Ok((input, ident)) } } pub(crate) fn entry_with_trailing<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlEntry, KdlParseError<&'a str>> + 'b { move |input| { let (input, mut leading) = recognize(many0(node_space(kdl_parser)))(input)?; if leading.is_empty() { leading = " "; }; let (input, mut entry) = alt(( property(kdl_parser), argument(kdl_parser), errant_plain_identifier(kdl_parser), ))(input)?; let (input, trailing) = recognize(many0(node_space(kdl_parser)))(input)?; entry.set_leading(leading); entry.set_trailing(trailing); Ok((input, entry)) } } fn entry<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlEntry, KdlParseError<&'a str>> + 'b { move |input| { let (input, leading) = recognize(many1(node_space(kdl_parser)))(input)?; let (input, mut entry) = alt(( property(kdl_parser), argument(kdl_parser), errant_plain_identifier(kdl_parser), ))(input)?; entry.set_leading(leading); Ok((input, entry)) } } fn entry_maybe_space<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlEntry, KdlParseError<&'a str>> + 'b { move |input| { let (input, leading) = recognize(many0(node_space(kdl_parser)))(input)?; let (input, mut entry) = alt(( property(kdl_parser), argument(kdl_parser), errant_plain_identifier(kdl_parser), ))(input)?; entry.set_leading(leading); Ok((input, entry)) } } fn property<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlEntry, KdlParseError<&'a str>> + 'b { move |input| { let start = input; let (input, name) = identifier(kdl_parser)(input)?; let (input, _) = context("'=' after property name", tag("="))(input)?; let (input, ty) = opt(annotation(kdl_parser))(input)?; let (input, (raw, value)) = context("property value", cut(value))(input).map_err(|e| set_details(e, input, Some("invalid value"), Some("Please refer to https://github.com/kdl-org/kdl/blob/main/SPEC.md#value for valid KDL value syntaxes.")))?; let mut entry = KdlEntry::new_prop(name, value); entry.ty = ty; entry.set_trailing(""); entry.set_value_repr(raw); #[cfg(feature = "span")] entry.set_span(kdl_parser.span_from_before_and_after(start, input)); Ok((input, entry)) } } fn argument<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlEntry, KdlParseError<&'a str>> + 'b { move |input| { let start = input; let (input, ty) = opt(annotation(kdl_parser))(input)?; let (input, (raw, value)) = if ty.is_some() { context("valid value", cut(value))(input) } else { context("valid value", value)(input) }?; let mut entry = KdlEntry::new(value); entry.ty = ty; entry.set_trailing(""); entry.set_value_repr(raw); #[cfg(feature = "span")] entry.set_span(kdl_parser.span_from_before_and_after(start, input)); Ok((input, entry)) } } fn value(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { alt(( null, boolean, string, raw_string, hexadecimal, octal, binary, float, integer, ))(input) } fn children<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, (&'a str, KdlDocument), KdlParseError<&'a str>> + 'b { move |input| { let (input, before) = recognize(many0(node_space(kdl_parser)))(input)?; let start = input; let (input, _) = tag("{")(input)?; let (input, children) = document(kdl_parser)(input)?; let (input, _) = cut(context("closing '}' in node children block", tag("}")))(input) .map_err(|e| set_details(e, start, Some("children block body"), None))?; Ok((input, (before, children))) } } fn annotation<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, KdlIdentifier, KdlParseError<&'a str>> + 'b { move |input| { let start = input; let (input, _) = tag("(")(input)?; let (input, ty) = cut(identifier(kdl_parser))(input)?; let (input, _) = context("closing ')' for type annotation", cut(tag(")")))(input) .map_err(|e| set_details(e, start, Some("annotation"), Some("annotations can only be KDL identifiers (including string identifiers), and can't have any space inside the parentheses.")))?; Ok((input, ty)) } } fn all_whitespace<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, &'a str, KdlParseError<&'a str>> + 'b { move |input| recognize(many0(alt((comment(kdl_parser), unicode_space, newline))))(input) } fn whitespace(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { recognize(alt((unicode_space, multi_line_comment)))(input) } fn linespace(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { recognize(alt((unicode_space, newline, single_line_comment)))(input) } fn node_space<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, &'a str, KdlParseError<&'a str>> + 'b { move |input| { context( "node space", recognize(alt(( delimited(many0(whitespace), escline, many0(whitespace)), recognize(many1(whitespace)), node_slashdash(kdl_parser), ))), )(input) } } fn escline(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { recognize(preceded( tag("\\"), context( "newline after line escape", cut(preceded( many0(whitespace), alt((single_line_comment, newline)), )), ), ))(input).map_err(|e| set_details(e, input, Some("line escape starts here"), Some("line escapes can only be followed by whitespace plus a newline (or single-line comment)."))) } fn unicode_space(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { alt(( tag(" "), tag("\t"), tag("\u{FEFF}"), // BOM tag("\u{00A0}"), tag("\u{1680}"), tag("\u{2000}"), tag("\u{2001}"), tag("\u{2002}"), tag("\u{2003}"), tag("\u{2004}"), tag("\u{2005}"), tag("\u{2006}"), tag("\u{2007}"), tag("\u{2008}"), tag("\u{2009}"), tag("\u{200A}"), tag("\u{202F}"), tag("\u{205F}"), tag("\u{3000}"), ))(input) } /// `newline := All line-break unicode white_space pub(crate) fn newline(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { alt(( tag("\r\n"), tag("\r"), tag("\n"), tag("\u{0085}"), tag("\u{000C}"), tag("\u{2028}"), tag("\u{2029}"), ))(input) } fn comment<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, &'a str, KdlParseError<&'a str>> + 'b { move |input| { alt(( single_line_comment, multi_line_comment, slashdash_comment(kdl_parser), ))(input) } } /// `single-line-comment := '//' ('\r' [^\n] | [^\r\n])* (newline | eof)` fn single_line_comment(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { recognize(preceded( tag("//"), cut(many_till( anychar, context("newline or eof after //", alt((newline, eof))), )), ))(input) .map_err(|e| set_details(e, input, Some("comment"), None)) } /// `multi-line-comment := '/*' commented-block fn multi_line_comment(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { recognize(preceded( tag("/*"), context("comment block body", cut(commented_block)), ))(input) .map_err(|e| set_details(e, input, Some("comment"), Some("multi-line comments must start with /* and be terminated with a matching */. They may be nested, but their */ must match."))) } /// `commented-block := '*/' | (multi-line-comment | '*' | '/' | [^*/]+) commented-block` fn commented_block(input: &str) -> IResult<&str, &str, KdlParseError<&str>> { alt(( tag("*/"), terminated( alt(( multi_line_comment, tag("*"), tag("/"), recognize(many_till(anychar, peek(alt((tag("*"), tag("/")))))), )), commented_block, ), ))(input) } fn node_slashdash<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, &'a str, KdlParseError<&'a str>> + 'b { move |input| { recognize(preceded( tag("/-"), context( "node following a slashdash", cut(alt(( recognize(entry_maybe_space(kdl_parser)), recognize(children(kdl_parser)), ))), ), ))(input) .map_err(|e| set_details(e, input, Some("slashdash"), None)) } } fn slashdash_comment<'a: 'b, 'b>( kdl_parser: &'b KdlParser<'a>, ) -> impl Fn(&'a str) -> IResult<&'a str, &'a str, KdlParseError<&'a str>> + 'b { move |input| { recognize(preceded(tag("/-"), cut(node(kdl_parser))))(input) .map_err(|e| set_details(e, input, Some("slashdash"), None)) } } fn boolean(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { alt(( map(tag("true"), |s: &str| (s.into(), KdlValue::Bool(true))), map(tag("false"), |s: &str| (s.into(), KdlValue::Bool(false))), ))(input) } fn null(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { map(tag("null"), |s: &str| (s.into(), KdlValue::Null))(input) } /// `escaped-string := '"' character* '"'` fn string(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { let (input, _) = tag("\"")(input)?; let mut original = String::new(); let mut value = String::new(); original.push('"'); let (input, chars) = many0(character)(input)?; for (raw, processed) in chars { original.push_str(raw); value.push(processed); } let (input, _) = cut(tag("\""))(input).map_err(|e| set_details(e, input, Some("string"), None))?; original.push('"'); Ok((input, (original, KdlValue::String(value)))) } /// `character := '\' escape | [^\"]` fn character(input: &str) -> IResult<&str, (&str, char), KdlParseError<&str>> { with_raw(alt((preceded(char('\\'), cut(escape)), none_of("\\\""))))(input) } /// This is like `recognize`, but _also_ returns the actual value. fn with_raw>, O, E: ParseError, F>( mut parser: F, ) -> impl FnMut(I) -> IResult where F: Parser, { move |input: I| { let i = input.clone(); match parser.parse(i) { Ok((i, x)) => { let index = input.offset(&i); Ok((i, (input.slice(..index), x))) } Err(e) => Err(e), } } } /// `escape := ["\\/bfnrt] | 'u{' hex-digit{1, 6} '}'` fn escape(input: &str) -> IResult<&str, char, KdlParseError<&str>> { alt(( delimited(tag("u{"), cut(unicode), char('}')), map_opt(anychar, |c| match c { '"' => Some('"'), '\\' => Some('\\'), '/' => Some('/'), 'b' => Some('\u{08}'), 'f' => Some('\u{0C}'), 'n' => Some('\n'), 'r' => Some('\r'), 't' => Some('\t'), _ => None, }), ))(input) } fn unicode(input: &str) -> IResult<&str, char, KdlParseError<&str>> { // TODO: This should only accept up to 0x10FFFF. map_opt( map_res( take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()), |hex| u32::from_str_radix(hex, 16), ), std::char::from_u32, )(input) } /// `raw-string := 'r' raw-string-hash` /// `raw-string-hash := '#' raw-string-hash '#' | raw-string-quotes` /// `raw-string-quotes := '"' .* '"'` fn raw_string(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { let mut raw = String::new(); let (input, _) = char('r')(input)?; raw.push('r'); let (input, hashes) = recognize(many0(char('#')))(input)?; raw.push_str(hashes); let (input, _) = char('"')(input)?; raw.push('"'); let close = format!("\"{}", hashes); let (input, value) = take_until(&close[..])(input)?; raw.push_str(value); let (input, _) = cut(tag(&close[..]))(input)?; raw.push_str(&close); Ok((input, (raw, KdlValue::RawString(value.into())))) } fn float(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { map_res( with_raw(alt(( recognize(tuple(( integer, opt(preceded(char('.'), cut(integer))), one_of("eE"), opt(one_of("+-")), cut(integer), ))), recognize(tuple((integer, char('.'), cut(integer)))), ))), |(raw, x)| { str::replace(x, "_", "") .parse::() .map(|x| (raw.into(), KdlValue::Base10Float(x))) }, )(input) .map_err(|e| { set_details( e, input, Some("invalid float"), Some( "Floating point numbers must be base 10, and have numbers after the decimal point.", ), ) }) } /// ```text /// integer := sign? [1-9] [0-9_]* /// sign := '+' | '-' /// ``` fn integer(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { let mut raw = String::new(); let (input, (raw_sign, sign)) = with_raw(sign)(input)?; raw.push_str(raw_sign); map_res( with_raw(recognize(many1(terminated( one_of("0123456789"), many0(char('_')), )))), move |(raw_int, out)| { raw.push_str(raw_int); str::replace(out, "_", "") .parse::() .map(move |x| x * sign) .map(|x| (raw.clone(), KdlValue::Base10(x))) }, )(input) } fn hexadecimal(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { let mut raw = String::new(); let (input, (raw_sign, sign)) = with_raw(sign)(input)?; raw.push_str(raw_sign); map_res( with_raw(preceded( alt((tag("0x"), tag("0X"))), context( "hexadecimal value", cut(recognize(many1(terminated( one_of("0123456789abcdefABCDEF"), many0(char('_')), )))), ), )), move |(raw_body, hex): (&str, &str)| { raw.push_str(raw_body); // TODO: Failure in case of int overflow! i64::from_str_radix(&str::replace(hex, "_", ""), 16) .map(|x| x * sign) .map(|x| (raw.clone(), KdlValue::Base16(x))) }, )(input) .map_err(|e| set_details(e, input, Some("invalid hexadecimal"), Some("Hexadecimal values can only include the characters 0-9 and a-f (case-insensitive), with optional `_` separators."))) } /// `octal := sign? '0o' [0-7] [0-7_]*` fn octal(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { let mut raw = String::new(); let (input, (raw_sign, sign)) = with_raw(sign)(input)?; raw.push_str(raw_sign); map_res( with_raw(preceded( alt((tag("0o"), tag("0O"))), context( "octal value", cut(recognize(many1(terminated( one_of("01234567"), many0(char('_')), )))), ), )), move |(raw_body, oct): (&str, &str)| { raw.push_str(raw_body); i64::from_str_radix(&str::replace(oct, "_", ""), 8) .map(|x| x * sign) .map(|x| (raw.clone(), KdlValue::Base8(x))) }, )(input) .map_err(|e| { set_details( e, input, Some("invalid octal"), Some("octal values can only include the characters 0-7, with optional `_` separators."), ) }) } /// `binary := sign? '0b' ('0' | '1') ('0' | '1' | '_')*` fn binary(input: &str) -> IResult<&str, (String, KdlValue), KdlParseError<&str>> { let mut raw = String::new(); let (input, (raw_sign, sign)) = with_raw(sign)(input)?; raw.push_str(raw_sign); map_res( with_raw(preceded( alt((tag("0b"), tag("0B"))), context( "binary value", cut(recognize(many1(terminated(one_of("01"), many0(char('_')))))), ), )), move |(raw_body, binary): (&str, &str)| { raw.push_str(raw_body); i64::from_str_radix(&str::replace(binary, "_", ""), 2) .map(|x| x * sign) .map(|x| (raw.clone(), KdlValue::Base2(x))) }, )(input) .map_err(|e| set_details(e, input, Some("invalid binary"), Some("Hexadecimal values can only include the characters 0 and 1, with optional `_` separators."))) } fn sign(input: &str) -> IResult<&str, i64, KdlParseError<&str>> { let (input, sign) = opt(alt((char('+'), char('-'))))(input)?; let mult = if let Some(sign) = sign { if sign == '+' { 1 } else { -1 } } else { 1 }; Ok((input, mult)) } #[cfg(test)] mod node_tests { use super::*; #[test] fn basic() { let input = "foo 1 \"bar\"=false"; let kdl_parser = crate::parser::KdlParser::new(input); match node(&kdl_parser)(input) { Ok(("", parsed)) => { let mut ident = KdlIdentifier::from("foo"); ident.set_repr("foo"); assert_eq!(parsed.name(), &ident); let mut entries = parsed.entries().iter(); let mut one = KdlEntry::new(1); one.set_leading(" "); one.set_trailing(""); one.set_value_repr("1"); assert_eq!(entries.next(), Some(&one)); let mut ident = KdlIdentifier::from("bar"); ident.set_repr("\"bar\""); let mut bar = KdlEntry::new_prop(ident, false); bar.set_leading(" "); bar.set_trailing(""); bar.set_value_repr("false"); assert_eq!(entries.next(), Some(&bar)); } Ok(_) => panic!("unexpected success"), Err(e) => { panic!("failed to parse: {:?}", e); } }; } #[test] fn errant_ident1() { let input = "struct Vec { }"; let kdl_parser = crate::parser::KdlParser::new(input); let res = kdl_parser.parse(document(&kdl_parser)); let e = res.unwrap_err(); check_span("Vec", &e.span, &input); assert_eq!(e.label, Some("plain identifiers can't be used here")); } #[test] fn errant_ident2() { let input = r##" some_node bad evil"##; let kdl_parser = crate::parser::KdlParser::new(input); let res = kdl_parser.parse(document(&kdl_parser)); let e = res.unwrap_err(); check_span("evil", &e.span, &input); assert_eq!(e.label, Some("plain identifiers can't be used here")); } #[test] fn errant_ident3() { let input = r##"node "ok" wait "fine""##; let kdl_parser = crate::parser::KdlParser::new(input); let res = kdl_parser.parse(document(&kdl_parser)); let e = res.unwrap_err(); check_span("wait", &e.span, &input); assert_eq!(e.label, Some("plain identifiers can't be used here")); } #[test] fn errant_ident4() { let input = r##"node x="ok" oof z="5"##; let kdl_parser = crate::parser::KdlParser::new(input); let res = kdl_parser.parse(document(&kdl_parser)); let e = res.unwrap_err(); check_span("oof", &e.span, &input); assert_eq!(e.label, Some("plain identifiers can't be used here")); } #[test] fn errant_ident5() { // NOTE: this one is a different situation and doesn't provide as good help still! // But at least it's clear that the value is bad, which is ok! let input = r##"node x=bad"##; let kdl_parser = crate::parser::KdlParser::new(input); let res = kdl_parser.parse(document(&kdl_parser)); let e = res.unwrap_err(); check_span("", &e.span, &input); assert_eq!(e.label, Some("invalid value")); } #[test] fn errant_ident6() { // NOTE: this one is a different situation and doesn't provide as good help still! // But at least it's clear that the value is bad, which is ok! let input = r##"node (int)bad"##; let kdl_parser = crate::parser::KdlParser::new(input); let res = kdl_parser.parse(document(&kdl_parser)); let e = res.unwrap_err(); check_span("", &e.span, &input); assert_eq!(e.label, None); } #[cfg(feature = "span")] #[track_caller] fn check_span(expected: &str, span: &SourceSpan, source: &impl miette::SourceCode) { let span = source.read_span(span, 0, 0).unwrap(); let span = std::str::from_utf8(span.data()).unwrap(); assert_eq!(span, expected); } } #[cfg(test)] mod whitespace_tests { #[test] fn basic() { use super::all_whitespace; let input = " \t\n\r"; let kdl_parser = crate::parser::KdlParser::new(input); assert_eq!(all_whitespace(&kdl_parser)(input), Ok(("", " \t\n\r"))); } } #[cfg(test)] mod comment_tests { use super::*; #[test] fn single_line() { let input = "// Hello world"; let kdl_parser = crate::parser::KdlParser::new(input); assert_eq!(comment(&kdl_parser)(input), Ok(("", "// Hello world"))); } #[test] fn multi_line() { let input = "/* Hello world */"; let kdl_parser = crate::parser::KdlParser::new(input); assert_eq!(comment(&kdl_parser)(input), Ok(("", "/* Hello world */"))); let input = "/* Hello /* world */ blah */"; let kdl_parser = crate::parser::KdlParser::new(input); assert_eq!( comment(&kdl_parser)(input), Ok(("", "/* Hello /* world */ blah */")) ); } #[test] fn slashdash() { let input = "/-foo 1 2"; let kdl_parser = crate::parser::KdlParser::new(input); assert_eq!(comment(&kdl_parser)(input), Ok(("", "/-foo 1 2"))); } #[test] fn surrounding() { // assert_eq!(trailing_comments("// foo"), Ok(("", vec!["// foo"]))); // assert_eq!(trailing_comments("/* foo */"), Ok(("", vec!["/* foo */"]))); // assert_eq!(trailing_comments("/* foo */ \n // bar"), Ok(("", vec!["/* foo */", "// bar"]))); } } #[cfg(test)] mod value_tests { use super::*; #[test] fn boolean_val() { assert_eq!( value("true"), Ok(("", ("true".into(), KdlValue::Bool(true)))) ); assert_eq!( value("false"), Ok(("", ("false".into(), KdlValue::Bool(false)))) ); } #[test] fn null_val() { assert_eq!(value("null"), Ok(("", ("null".into(), KdlValue::Null)))); } #[test] fn binary_val() { assert_eq!( value("0b0101"), Ok(("", ("0b0101".into(), KdlValue::Base2(0b0101)))) ); assert_eq!( value("0b0101_1111"), Ok(("", ("0b0101_1111".into(), KdlValue::Base2(0b0101_1111)))) ); assert_eq!( value("-0b0101"), Ok(("", ("-0b0101".into(), KdlValue::Base2(-0b0101)))) ); assert_eq!( value("+0b0101"), Ok(("", ("+0b0101".into(), KdlValue::Base2(0b0101)))) ); } #[test] fn octal_val() { assert_eq!( value("0o01234567"), Ok(("", ("0o01234567".into(), KdlValue::Base8(0o01234567)))) ); assert_eq!( value("0o123_4567"), Ok(("", ("0o123_4567".into(), KdlValue::Base8(0o1234567)))) ); assert_eq!( value("-0o123"), Ok(("", ("-0o123".into(), KdlValue::Base8(-0o123)))) ); assert_eq!( value("+0o123"), Ok(("", ("+0o123".into(), KdlValue::Base8(0o123)))) ); } #[test] fn hexadecimal_val() { assert_eq!( value("0x0123456789abcdef"), Ok(( "", ( "0x0123456789abcdef".into(), KdlValue::Base16(0x0123456789abcdef) ) )) ); let input = "node 0x0123_4567_89ab_cdef"; let kdl_parser = crate::parser::KdlParser::new(input); let (_, n) = node(&kdl_parser)(input).expect("failed to parse node"); assert_eq!(&n[0], &KdlValue::Base16(0x0123456789abcdef)); assert_eq!( value("0x123_4567"), Ok(("", ("0x123_4567".into(), KdlValue::Base16(0x1234567)))) ); assert_eq!( value("-0x123"), Ok(("", ("-0x123".into(), KdlValue::Base16(-0x123)))) ); assert_eq!( value("+0x123"), Ok(("", ("+0x123".into(), KdlValue::Base16(0x123)))) ); } #[test] fn integer_val() { assert_eq!( value("123_456"), Ok(("", ("123_456".into(), KdlValue::Base10(123456)))) ); assert_eq!( value("-123"), Ok(("", ("-123".into(), KdlValue::Base10(-123)))) ); assert_eq!( value("+123"), Ok(("", ("+123".into(), KdlValue::Base10(123)))) ); } #[test] fn float_val() { assert_eq!( value("123_456.789e-10"), Ok(( "", ( "123_456.789e-10".into(), KdlValue::Base10Float(123_456.789e-10) ) )) ); assert_eq!( value("-123.456"), Ok(("", ("-123.456".into(), KdlValue::Base10Float(-123.456)))) ); assert_eq!( value("+123.456"), Ok(("", ("+123.456".into(), KdlValue::Base10Float(123.456)))) ); } #[test] fn string_val() { assert_eq!( value(r#""Hello \n\u{2020}world""#), Ok(( "", ( r#""Hello \n\u{2020}world""#.into(), KdlValue::String("Hello \n\u{2020}world".into()) ) )) ); } #[test] fn raw_string_val() { assert_eq!( value(r#"r"Hello \n\u{2020}world""#), Ok(( "", ( r#"r"Hello \n\u{2020}world""#.into(), KdlValue::RawString(r"Hello \n\u{2020}world".into()) ) )) ); assert_eq!( value(r###"r##"Hello \n\u{2020}world"##"###), Ok(( "", ( r###"r##"Hello \n\u{2020}world"##"###.into(), KdlValue::RawString(r"Hello \n\u{2020}world".into()) ) )) ); } } kdl-4.6.0/src/value.rs000064400000000000000000000212270072674642500127120ustar 00000000000000use std::fmt::Display; /// A specific [KDL Value](https://github.com/kdl-org/kdl/blob/main/SPEC.md#value). #[derive(Debug, Clone, PartialEq)] pub enum KdlValue { /// A [KDL Raw String](https://github.com/kdl-org/kdl/blob/main/SPEC.md#raw-string). RawString(String), /// A [KDL String](https://github.com/kdl-org/kdl/blob/main/SPEC.md#string). String(String), /// A [KDL /// Number](https://github.com/kdl-org/kdl/blob/main/SPEC.md#number) in /// binary form (e.g. `0b010101`). Base2(i64), /// A [KDL /// Number](https://github.com/kdl-org/kdl/blob/main/SPEC.md#number) in /// octal form (e.g. `0o12345670`). Base8(i64), /// A [KDL /// Number](https://github.com/kdl-org/kdl/blob/main/SPEC.md#number) in /// decimal form (e.g. `1234567890`). Base10(i64), /// A [KDL /// Number](https://github.com/kdl-org/kdl/blob/main/SPEC.md#number) in /// decimal form (e.g. `1234567890.123`), interpreted as a Rust f64. Base10Float(f64), /// A [KDL /// Number](https://github.com/kdl-org/kdl/blob/main/SPEC.md#number) in /// hexadecimal form (e.g. `1234567890abcdef`). Base16(i64), /// A [KDL Boolean](https://github.com/kdl-org/kdl/blob/main/SPEC.md#boolean). Bool(bool), /// The [KDL Null Value](https://github.com/kdl-org/kdl/blob/main/SPEC.md#null). Null, } impl KdlValue { /// Returns `true` if the value is a [`KdlValue::RawString`]. pub fn is_raw_string(&self) -> bool { matches!(self, Self::RawString(..)) } /// Returns `true` if the value is a [`KdlValue::String`]. pub fn is_string(&self) -> bool { matches!(self, Self::String(..)) } /// Returns `true` if the value is a [`KdlValue::String`] or [`KdlValue::RawString`]. pub fn is_string_value(&self) -> bool { matches!(self, Self::String(..) | Self::RawString(..)) } /// Returns `true` if the value is a [`KdlValue::Base2`]. pub fn is_base2(&self) -> bool { matches!(self, Self::Base2(..)) } /// Returns `true` if the value is a [`KdlValue::Base8`]. pub fn is_base8(&self) -> bool { matches!(self, Self::Base8(..)) } /// Returns `true` if the value is a [`KdlValue::Base10`]. pub fn is_base10(&self) -> bool { matches!(self, Self::Base10(..)) } /// Returns `true` if the value is a [`KdlValue::Base16`]. pub fn is_base16(&self) -> bool { matches!(self, Self::Base16(..)) } /// Returns `true` if the value is a [`KdlValue::Base2`], /// [`KdlValue::Base8`], [`KdlValue::Base10`], or [`KdlValue::Base16`]. pub fn is_i64_value(&self) -> bool { matches!( self, Self::Base2(..) | Self::Base8(..) | Self::Base10(..) | Self::Base16(..) ) } /// Returns `true` if the value is a [`KdlValue::Base10Float`]. pub fn is_base10_float(&self) -> bool { matches!(self, Self::Base10Float(..)) } /// Returns `true` if the value is a [`KdlValue::Base10Float`]. pub fn is_float_value(&self) -> bool { matches!(self, Self::Base10Float(..)) } /// Returns `true` if the value is a [`KdlValue::Bool`]. pub fn is_bool(&self) -> bool { matches!(self, Self::Bool(..)) } /// Returns `true` if the value is a [`KdlValue::Null`]. pub fn is_null(&self) -> bool { matches!(self, Self::Null) } /// Returns `Some(&str)` if the `KdlValue` is a [`KdlValue::RawString`] or a /// [`KdlValue::String`], otherwise returns `None`. pub fn as_string(&self) -> Option<&str> { use KdlValue::*; match self { String(s) | RawString(s) => Some(s), _ => None, } } /// Returns `Some(i64)` if the `KdlValue` is a [`KdlValue::Base2`], /// [`KdlValue::Base8`], [`KdlValue::Base10`], or [`KdlValue::Base16`], /// otherwise returns `None`. pub fn as_i64(&self) -> Option { use KdlValue::*; match self { Base2(i) | Base8(i) | Base10(i) | Base16(i) => Some(*i), _ => None, } } /// Returns `Some(f64)` if the `KdlValue` is a [`KdlValue::Base10Float`], /// otherwise returns `None`. pub fn as_f64(&self) -> Option { if let Self::Base10Float(v) = self { Some(*v) } else { None } } /// Returns `Some(bool)` if the `KdlValue` is a [`KdlValue::Bool`], otherwise returns `None`. pub fn as_bool(&self) -> Option { if let Self::Bool(v) = self { Some(*v) } else { None } } } impl Display for KdlValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::RawString(_) => self.write_raw_string(f), Self::String(_) => self.write_string(f), Self::Base2(value) => write!(f, "0b{:b}", value), Self::Base8(value) => write!(f, "0o{:o}", value), Self::Base10(value) => write!(f, "{:?}", value), Self::Base10Float(value) => write!( f, "{:?}", if value == &f64::INFINITY { f64::MAX } else if value == &f64::NEG_INFINITY { -f64::MAX } else if value.is_nan() { 0.0 } else { *value } ), Self::Base16(value) => write!(f, "0x{:x}", value), Self::Bool(value) => write!(f, "{}", value), Self::Null => write!(f, "null"), } } } impl KdlValue { fn write_string(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let string = self.as_string().unwrap(); write!(f, "\"")?; for char in string.chars() { match char { '\\' | '"' => write!(f, "\\{}", char)?, '\n' => write!(f, "\\n")?, '\r' => write!(f, "\\r")?, '\t' => write!(f, "\\t")?, '\u{08}' => write!(f, "\\b")?, '\u{0C}' => write!(f, "\\f")?, _ => write!(f, "{}", char)?, } } write!(f, "\"")?; Ok(()) } fn write_raw_string(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let raw = self.as_string().unwrap(); let mut consecutive = 0usize; let mut maxhash = 0usize; for char in raw.chars() { if char == '#' { consecutive += 1; } else if char == '"' { maxhash = maxhash.max(consecutive + 1); } else { consecutive = 0; } } write!(f, "r")?; write!(f, "{}", "#".repeat(maxhash))?; write!(f, "\"{}\"", raw)?; write!(f, "{}", "#".repeat(maxhash))?; Ok(()) } } impl From for KdlValue { fn from(value: i64) -> Self { KdlValue::Base10(value) } } impl From for KdlValue { fn from(value: f64) -> Self { KdlValue::Base10Float(value) } } impl From<&str> for KdlValue { fn from(value: &str) -> Self { KdlValue::String(value.to_string()) } } impl From for KdlValue { fn from(value: String) -> Self { KdlValue::String(value) } } impl From for KdlValue { fn from(value: bool) -> Self { KdlValue::Bool(value) } } impl From> for KdlValue where T: Into, { fn from(value: Option) -> Self { match value { Some(value) => value.into(), None => KdlValue::Null, } } } #[cfg(test)] mod test { use super::*; #[test] fn formatting() { let raw = KdlValue::RawString(r###"r##"foor#"bar"#baz"##"###.into()); assert_eq!( format!("{}", raw), r####"r###"r##"foor#"bar"#baz"##"###"#### ); let string = KdlValue::String("foo\n".into()); assert_eq!(format!("{}", string), r#""foo\n""#); let base2 = KdlValue::Base2(0b1010_1010); assert_eq!(format!("{}", base2), "0b10101010"); let base8 = KdlValue::Base8(0o12345670); assert_eq!(format!("{}", base8), "0o12345670"); let base10 = KdlValue::Base10(1234567890); assert_eq!(format!("{}", base10), "1234567890"); let base10float = KdlValue::Base10Float(1234567890.12345); assert_eq!(format!("{}", base10float), "1234567890.12345"); let base16 = KdlValue::Base16(0x1234567890ABCDEF); assert_eq!(format!("{}", base16), "0x1234567890abcdef"); let boolean = KdlValue::Bool(true); assert_eq!(format!("{}", boolean), "true"); let null = KdlValue::Null; assert_eq!(format!("{}", null), "null"); } } kdl-4.6.0/tests/README.md000064400000000000000000000061150072674642500130610ustar 00000000000000# Full Document Test Cases The `input` folder contains test cases for KDL parsers. The `expected_kdl` folder contains files with the same name as those in `input` with the expected output after being run through the parser and printed out again. If there's no file in `expected_kdl` with a name corresponding to one in `input` it indicates that parsing for that case should fail. ## Translation Rules By necessity, the files in `expected_kdl` are not identical to their corresponding inputs. They are instead pretty-printed according to the following rules: * All comments removed * Extra empty lines removed except for a newline after the last node * All nodes should be reformatted without escaped newlines * Node fields should be `identifier ` * All values and all children must be in the same order as they were defined. * Properties must be in _alphabetical order_ and separated by a single space. * All strings must be represented as regular strings, with appropriate escapes for invalid bare characters. That means that raw strings must be converted to plain strings, and escaped. * Any literal newlines or other ascii escape characters in escaped strings replaced with their escape sequences. * All identifiers must be unquoted unless they _must_ be quoted. That means `"foo"` becomes `foo`, and `"foo bar"` stays that way. * Any duplicate properties must be removed, with only the rightmost one remaining. This also means duplicate properties must be allowed. * 4 space indents * All numbers must be converted to their simplest decimal representation. That means that hex, octal, and binary must all be converted to decimals. All floats must be represented using `E` notation, with a single digit left of the decimal point if the float is less than 1. While parsers are required to _consume_ different number syntaxes, they are under no obligation to represent numbers in any particular way. Data may be manipulated as you wish in order to output the expected KDL. This test suite verifies the ability to **parse**, not specific quirks about internal representations. ## What to do if a test fails for you This test suite was originally designed for a pre-1.0 version of the KDL specification. If you encounter a failure, it's likely that the test suite will need to be updated, rather than your parser itself. This test suite is NOT AUTHORITATIVE. If this test suite disagrees with the KDL spec in any way, the most desirable resolution is to send a PR to this repository to fix the test itself. Likewise, if you think a test succeeded but should not have, please send a PR. If you think the disagreement is due to a genuine error or oversight in the KDL specification, please open an issue explaining the matter and the change will be considered for the next version of the KDL spec. ## Credit This test suite was extracted from [`kdl4j`](https://github.com/hkolbeck/kdl4j), the original Java implementation of KDL, with huge thanks to [@hkolbeck](https://github.com/hkolbeck) for authoring them! kdl-4.6.0/tests/compliance.rs000064400000000000000000000110120072674642500142520ustar 00000000000000use std::{ collections::HashMap, fs, path::{Path, PathBuf}, }; use kdl::{KdlDocument, KdlError, KdlIdentifier, KdlValue}; use miette::IntoDiagnostic; #[test] fn spec_compliance() -> miette::Result<()> { let input = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests") .join("test_cases") .join("input"); for test_name in fs::read_dir(&input).into_diagnostic()? { let test_path = test_name.into_diagnostic()?.path(); println!( "parsing {}:", PathBuf::from(test_path.file_name().unwrap()).display() ); let src = normalize_line_endings(fs::read_to_string(&test_path).into_diagnostic()?); println!("src: {}", src); let res: Result = src.parse(); validate_res(res, &test_path)?; } Ok(()) } fn validate_res(res: Result, path: &Path) -> miette::Result<()> { let file_name = path.file_name().unwrap(); let expected_dir = path .parent() .unwrap() .parent() .unwrap() .join("expected_kdl"); let expected_path = expected_dir.join(file_name); let underscored = expected_dir.join(&format!("_{}", PathBuf::from(file_name).display())); if expected_path.exists() { let doc = res?; let expected = normalize_line_endings(fs::read_to_string(&expected_path).into_diagnostic()?); println!("expected: {}", expected); let stringified = stringify_to_expected(doc); println!("stringified: {}", stringified); assert_eq!(stringified, expected); } else if underscored.exists() { println!( "skipped reserialization for {}", PathBuf::from(file_name).display() ); } else { assert!(res.is_err(), "parse should not have succeeded"); } Ok(()) } fn normalize_line_endings(src: String) -> String { src.replace("\r\n", "\n") } fn stringify_to_expected(mut doc: KdlDocument) -> String { doc.fmt_no_comments(); normalize_numbers(&mut doc); normalize_strings(&mut doc); dedupe_props(&mut doc); remove_empty_children(&mut doc); doc.to_string() } fn normalize_numbers(doc: &mut KdlDocument) { for node in doc.nodes_mut() { for entry in node.entries_mut() { if let Some(value) = entry.value().as_i64() { *entry.value_mut() = KdlValue::Base10(value); } } if let Some(children) = node.children_mut() { normalize_numbers(children); } } } fn normalize_strings(doc: &mut KdlDocument) { for node in doc.nodes_mut() { for entry in node.entries_mut() { if let Some(value) = entry.value().as_string() { *entry.value_mut() = KdlValue::String(value.to_string()); } } if let Some(children) = node.children_mut() { normalize_strings(children); } } } fn dedupe_props(doc: &mut KdlDocument) { for node in doc.nodes_mut() { let mut props = HashMap::>::new(); for (idx, entry) in node.entries_mut().iter_mut().enumerate() { if let Some(name) = entry.name() { if !props.contains_key(name) { props.insert(name.clone(), Vec::new()); } if let Some(indices) = props.get_mut(name) { indices.push(idx); } } } let new_entries = node .entries() .iter() .enumerate() .filter_map(|(idx, entry)| { if let Some(name) = entry.name() { if let Some(indices) = props.get(name) { if &idx == indices.last().unwrap() { return Some(entry.clone()); } else { return None; } } } Some(entry.clone()) }); *node.entries_mut() = new_entries.collect(); if let Some(children) = node.children_mut() { dedupe_props(children); } } } fn remove_empty_children(doc: &mut KdlDocument) { for node in doc.nodes_mut() { let maybe_children = node.children_mut(); if maybe_children.is_some() && maybe_children.as_ref().unwrap().nodes().is_empty() { *maybe_children = None; } if let Some(children) = maybe_children { remove_empty_children(children); } } } kdl-4.6.0/tests/formatting.rs000064400000000000000000000010070072674642500143150ustar 00000000000000use kdl::{KdlDocument, KdlNode}; #[test] fn build_and_format() { let mut c = KdlNode::new("c"); c.ensure_children(); let mut b = KdlNode::new("b"); b.ensure_children().nodes_mut().push(c); let mut a = KdlNode::new("a"); a.ensure_children().nodes_mut().push(b); let mut doc = KdlDocument::new(); doc.nodes_mut().push(a); doc.fmt(); let fmt = doc.to_string(); println!("{}", fmt); assert_eq!( fmt, r#"a { b { c { } } } "# ); } kdl-4.6.0/tests/test_cases/expected_kdl/_negative_exponent.kdl000064400000000000000000000000130072674642500227360ustar 00000000000000node 1e-10 kdl-4.6.0/tests/test_cases/expected_kdl/_parse_all_arg_types.kdl000064400000000000000000000001050072674642500232350ustar 00000000000000node 1 1.0 10000000000.0 1e-10 1 7 2 "arg" "arg\\\\" true false null kdl-4.6.0/tests/test_cases/expected_kdl/_positive_exponent.kdl000064400000000000000000000000230072674642500227770ustar 00000000000000node 10000000000.0 kdl-4.6.0/tests/test_cases/expected_kdl/_sci_notation_large.kdl000064400000000000000000000000250072674642500230620ustar 00000000000000node prop=1.23E+1000 kdl-4.6.0/tests/test_cases/expected_kdl/_sci_notation_small.kdl000064400000000000000000000000250072674642500231000ustar 00000000000000node prop=1.23E-1000 kdl-4.6.0/tests/test_cases/expected_kdl/_underscore_in_exponent.kdl000064400000000000000000000000140072674642500237740ustar 00000000000000node 1e-100 kdl-4.6.0/tests/test_cases/expected_kdl/all_escapes.kdl000064400000000000000000000000270072674642500213350ustar 00000000000000node "\"\\/\b\f\n\r\t" kdl-4.6.0/tests/test_cases/expected_kdl/all_node_fields.kdl000064400000000000000000000000510072674642500221620ustar 00000000000000node "arg" prop="val" { inner_node } kdl-4.6.0/tests/test_cases/expected_kdl/arg_and_prop_same_name.kdl000064400000000000000000000000250072674642500235200ustar 00000000000000node "arg" arg="val" kdl-4.6.0/tests/test_cases/expected_kdl/arg_false_type.kdl000064400000000000000000000000210072674642500220400ustar 00000000000000node (type)false kdl-4.6.0/tests/test_cases/expected_kdl/arg_float_type.kdl000064400000000000000000000000170072674642500220600ustar 00000000000000node (type)2.5 kdl-4.6.0/tests/test_cases/expected_kdl/arg_hex_type.kdl000064400000000000000000000000160072674642500215360ustar 00000000000000node (type)16 kdl-4.6.0/tests/test_cases/expected_kdl/arg_null_type.kdl000064400000000000000000000000200072674642500217170ustar 00000000000000node (type)null kdl-4.6.0/tests/test_cases/expected_kdl/arg_raw_string_type.kdl000064400000000000000000000000210072674642500231250ustar 00000000000000node (type)"str" kdl-4.6.0/tests/test_cases/expected_kdl/arg_string_type.kdl000064400000000000000000000000210072674642500222540ustar 00000000000000node (type)"str" kdl-4.6.0/tests/test_cases/expected_kdl/arg_true_type.kdl000064400000000000000000000000200072674642500217240ustar 00000000000000node (type)true kdl-4.6.0/tests/test_cases/expected_kdl/arg_type.kdl000064400000000000000000000000210072674642500206660ustar 00000000000000node (type)"arg" kdl-4.6.0/tests/test_cases/expected_kdl/arg_zero_type.kdl000064400000000000000000000000150072674642500217300ustar 00000000000000node (type)0 kdl-4.6.0/tests/test_cases/expected_kdl/asterisk_in_block_comment.kdl000064400000000000000000000000050072674642500242650ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/bare_emoji.kdl000064400000000000000000000000160072674642500211540ustar 00000000000000😁 "happy!" kdl-4.6.0/tests/test_cases/expected_kdl/binary.kdl000064400000000000000000000000070072674642500203440ustar 00000000000000node 2 kdl-4.6.0/tests/test_cases/expected_kdl/binary_trailing_underscore.kdl000064400000000000000000000000070072674642500244660ustar 00000000000000node 2 kdl-4.6.0/tests/test_cases/expected_kdl/binary_underscore.kdl000064400000000000000000000000070072674642500225750ustar 00000000000000node 2 kdl-4.6.0/tests/test_cases/expected_kdl/blank_arg_type.kdl000064400000000000000000000000140072674642500220370ustar 00000000000000node ("")10 kdl-4.6.0/tests/test_cases/expected_kdl/blank_node_type.kdl000064400000000000000000000000110072674642500222100ustar 00000000000000("")node kdl-4.6.0/tests/test_cases/expected_kdl/blank_prop_type.kdl000064400000000000000000000000220072674642500222450ustar 00000000000000node key=("")true kdl-4.6.0/tests/test_cases/expected_kdl/block_comment.kdl000064400000000000000000000000130072674642500216710ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/block_comment_after_node.kdl000064400000000000000000000000130072674642500240570ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/block_comment_before_node.kdl000064400000000000000000000000050072674642500242210ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/block_comment_before_node_no_space.kdl000064400000000000000000000000050072674642500260700ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/block_comment_newline.kdl000064400000000000000000000000010072674642500234070ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/boolean_arg.kdl000064400000000000000000000000200072674642500213230ustar 00000000000000node false true kdl-4.6.0/tests/test_cases/expected_kdl/boolean_prop.kdl000064400000000000000000000000340072674642500215370ustar 00000000000000node prop1=true prop2=false kdl-4.6.0/tests/test_cases/expected_kdl/commented_arg.kdl000064400000000000000000000000140072674642500216620ustar 00000000000000node "arg2" kdl-4.6.0/tests/test_cases/expected_kdl/commented_child.kdl000064400000000000000000000000130072674642500221730ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/commented_line.kdl000064400000000000000000000000070072674642500220420ustar 00000000000000node_2 kdl-4.6.0/tests/test_cases/expected_kdl/commented_node.kdl000064400000000000000000000000070072674642500220400ustar 00000000000000node_2 kdl-4.6.0/tests/test_cases/expected_kdl/commented_prop.kdl000064400000000000000000000000130072674642500220700ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/crlf_between_nodes.kdl000064400000000000000000000000140072674642500227050ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/expected_kdl/emoji.kdl000064400000000000000000000000140072674642500201610ustar 00000000000000node "😀" kdl-4.6.0/tests/test_cases/expected_kdl/empty.kdl000064400000000000000000000000010072674642500202100ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/empty_child.kdl000064400000000000000000000000050072674642500213570ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/empty_child_different_lines.kdl000064400000000000000000000000050072674642500245770ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/empty_child_same_line.kdl000064400000000000000000000000050072674642500233730ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/empty_child_whitespace.kdl000064400000000000000000000000050072674642500235730ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/empty_quoted_node_id.kdl000064400000000000000000000000110072674642500232530ustar 00000000000000"" "arg" kdl-4.6.0/tests/test_cases/expected_kdl/empty_quoted_prop_key.kdl000064400000000000000000000000200072674642500235020ustar 00000000000000node ""="empty" kdl-4.6.0/tests/test_cases/expected_kdl/empty_string_arg.kdl000064400000000000000000000000100072674642500224270ustar 00000000000000node "" kdl-4.6.0/tests/test_cases/expected_kdl/esc_newline_in_string.kdl000064400000000000000000000000240072674642500234260ustar 00000000000000node "hello\nworld" kdl-4.6.0/tests/test_cases/expected_kdl/esc_unicode_in_string.kdl000064400000000000000000000000240072674642500234130ustar 00000000000000node "hello\nworld" kdl-4.6.0/tests/test_cases/expected_kdl/escline.kdl000064400000000000000000000000130072674642500204770ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/escline_line_comment.kdl000064400000000000000000000000240072674642500232320ustar 00000000000000node "arg" "arg2\n" kdl-4.6.0/tests/test_cases/expected_kdl/escline_node.kdl000064400000000000000000000000140072674642500215050ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/expected_kdl/false_prefix_in_bare_id.kdl000064400000000000000000000000110072674642500236550ustar 00000000000000false_id kdl-4.6.0/tests/test_cases/expected_kdl/false_prefix_in_prop_key.kdl000064400000000000000000000000200072674642500241200ustar 00000000000000node false_id=1 kdl-4.6.0/tests/test_cases/expected_kdl/hex.kdl000064400000000000000000000000310072674642500176410ustar 00000000000000node 1311768467294899695 kdl-4.6.0/tests/test_cases/expected_kdl/hex_int.kdl000064400000000000000000000000310072674642500205130ustar 00000000000000node 1311768467294899695 kdl-4.6.0/tests/test_cases/expected_kdl/hex_int_underscores.kdl000064400000000000000000000000220072674642500231270ustar 00000000000000node 737894400291 kdl-4.6.0/tests/test_cases/expected_kdl/hex_leading_zero.kdl000064400000000000000000000000070072674642500223660ustar 00000000000000node 1 kdl-4.6.0/tests/test_cases/expected_kdl/int_multiple_underscore.kdl000064400000000000000000000000120072674642500240120ustar 00000000000000node 1234 kdl-4.6.0/tests/test_cases/expected_kdl/just_block_comment.kdl000064400000000000000000000000010072674642500227330ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/just_child.kdl000064400000000000000000000000300072674642500212040ustar 00000000000000node { inner_node } kdl-4.6.0/tests/test_cases/expected_kdl/just_newline.kdl000064400000000000000000000000010072674642500215600ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/just_node_id.kdl000064400000000000000000000000050072674642500215240ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/just_space.kdl000064400000000000000000000000010072674642500212120ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/leading_newline.kdl000064400000000000000000000000050072674642500222020ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/leading_zero_binary.kdl000064400000000000000000000000070072674642500230660ustar 00000000000000node 1 kdl-4.6.0/tests/test_cases/expected_kdl/leading_zero_int.kdl000064400000000000000000000000100072674642500223660ustar 00000000000000node 11 kdl-4.6.0/tests/test_cases/expected_kdl/leading_zero_oct.kdl000064400000000000000000000000070072674642500223670ustar 00000000000000node 1 kdl-4.6.0/tests/test_cases/expected_kdl/multiline_comment.kdl000064400000000000000000000000130072674642500226010ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/multiline_nodes.kdl000064400000000000000000000000230072674642500222500ustar 00000000000000node "arg1" "arg2" kdl-4.6.0/tests/test_cases/expected_kdl/multiline_string.kdl000064400000000000000000000000430072674642500224500ustar 00000000000000node " hey\neveryone\nhow goes?\n" kdl-4.6.0/tests/test_cases/expected_kdl/negative_float.kdl000064400000000000000000000000240072674642500220460ustar 00000000000000node -1.0 key=-10.0 kdl-4.6.0/tests/test_cases/expected_kdl/negative_int.kdl000064400000000000000000000000220072674642500215310ustar 00000000000000node -10 prop=-15 kdl-4.6.0/tests/test_cases/expected_kdl/nested_block_comment.kdl000064400000000000000000000000130072674642500232330ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/nested_children.kdl000064400000000000000000000000510072674642500222110ustar 00000000000000node1 { node2 { node } } kdl-4.6.0/tests/test_cases/expected_kdl/nested_comments.kdl000064400000000000000000000000130072674642500222440ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/nested_multiline_block_comment.kdl000064400000000000000000000000130072674642500253150ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/newline_between_nodes.kdl000064400000000000000000000000140072674642500234200ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/expected_kdl/newlines_in_block_comment.kdl000064400000000000000000000000130072674642500242630ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/no_decimal_exponent.kdl000064400000000000000000000000230072674642500230700ustar 00000000000000node 10000000000.0 kdl-4.6.0/tests/test_cases/expected_kdl/node_false.kdl000064400000000000000000000000130072674642500211540ustar 00000000000000node false kdl-4.6.0/tests/test_cases/expected_kdl/node_true.kdl000064400000000000000000000000120072674642500210400ustar 00000000000000node true kdl-4.6.0/tests/test_cases/expected_kdl/node_type.kdl000064400000000000000000000000130072674642500210430ustar 00000000000000(type)node kdl-4.6.0/tests/test_cases/expected_kdl/null_arg.kdl000064400000000000000000000000120072674642500206570ustar 00000000000000node null kdl-4.6.0/tests/test_cases/expected_kdl/null_prefix_in_bare_id.kdl000064400000000000000000000000100072674642500235340ustar 00000000000000null_id kdl-4.6.0/tests/test_cases/expected_kdl/null_prefix_in_prop_key.kdl000064400000000000000000000000170072674642500240060ustar 00000000000000node null_id=1 kdl-4.6.0/tests/test_cases/expected_kdl/null_prop.kdl000064400000000000000000000000170072674642500210730ustar 00000000000000node prop=null kdl-4.6.0/tests/test_cases/expected_kdl/numeric_arg.kdl000064400000000000000000000000120072674642500213470ustar 00000000000000node 15.7 kdl-4.6.0/tests/test_cases/expected_kdl/numeric_prop.kdl000064400000000000000000000000170072674642500215630ustar 00000000000000node prop=10.0 kdl-4.6.0/tests/test_cases/expected_kdl/octal.kdl000064400000000000000000000000160072674642500201620ustar 00000000000000node 16434824 kdl-4.6.0/tests/test_cases/expected_kdl/only_cr.kdl000064400000000000000000000000010072674642500205170ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/only_line_comment.kdl000064400000000000000000000000010072674642500225640ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/only_line_comment_crlf.kdl000064400000000000000000000000010072674642500235720ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/only_line_comment_newline.kdl000064400000000000000000000000010072674642500243050ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/positive_int.kdl000064400000000000000000000000100072674642500215660ustar 00000000000000node 10 kdl-4.6.0/tests/test_cases/expected_kdl/preserve_duplicate_nodes.kdl000064400000000000000000000000120072674642500241310ustar 00000000000000node node kdl-4.6.0/tests/test_cases/expected_kdl/preserve_node_order.kdl000064400000000000000000000000220072674642500231100ustar 00000000000000node2 node5 node1 kdl-4.6.0/tests/test_cases/expected_kdl/prop_false_type.kdl000064400000000000000000000000250072674642500222530ustar 00000000000000node key=(type)false kdl-4.6.0/tests/test_cases/expected_kdl/prop_float_type.kdl000064400000000000000000000000350072674642500222670ustar 00000000000000node key=(type)25000000000.0 kdl-4.6.0/tests/test_cases/expected_kdl/prop_hex_type.kdl000064400000000000000000000000220072674642500217420ustar 00000000000000node key=(type)16 kdl-4.6.0/tests/test_cases/expected_kdl/prop_null_type.kdl000064400000000000000000000000240072674642500221320ustar 00000000000000node key=(type)null kdl-4.6.0/tests/test_cases/expected_kdl/prop_raw_string_type.kdl000064400000000000000000000000250072674642500233400ustar 00000000000000node key=(type)"str" kdl-4.6.0/tests/test_cases/expected_kdl/prop_string_type.kdl000064400000000000000000000000250072674642500224670ustar 00000000000000node key=(type)"str" kdl-4.6.0/tests/test_cases/expected_kdl/prop_true_type.kdl000064400000000000000000000000240072674642500221370ustar 00000000000000node key=(type)true kdl-4.6.0/tests/test_cases/expected_kdl/prop_type.kdl000064400000000000000000000000240072674642500211000ustar 00000000000000node key=(type)true kdl-4.6.0/tests/test_cases/expected_kdl/prop_zero_type.kdl000064400000000000000000000000210072674642500221340ustar 00000000000000node key=(type)0 kdl-4.6.0/tests/test_cases/expected_kdl/quoted_arg_type.kdl000064400000000000000000000000210072674642500222470ustar 00000000000000node ("type/")10 kdl-4.6.0/tests/test_cases/expected_kdl/quoted_node_name.kdl000064400000000000000000000000100072674642500223600ustar 00000000000000"0node" kdl-4.6.0/tests/test_cases/expected_kdl/quoted_node_type.kdl000064400000000000000000000000160072674642500224270ustar 00000000000000("type/")node kdl-4.6.0/tests/test_cases/expected_kdl/quoted_numeric.kdl000064400000000000000000000000210072674642500220770ustar 00000000000000node prop="10.0" kdl-4.6.0/tests/test_cases/expected_kdl/quoted_prop_name.kdl000064400000000000000000000000230072674642500224170ustar 00000000000000node "0prop"="val" kdl-4.6.0/tests/test_cases/expected_kdl/quoted_prop_type.kdl000064400000000000000000000000270072674642500224640ustar 00000000000000node key=("type/")true kdl-4.6.0/tests/test_cases/expected_kdl/r_node.kdl000064400000000000000000000000100072674642500203200ustar 00000000000000r "arg" kdl-4.6.0/tests/test_cases/expected_kdl/raw_arg_type.kdl000064400000000000000000000000200072674642500215360ustar 00000000000000node (type)true kdl-4.6.0/tests/test_cases/expected_kdl/raw_node_name.kdl000064400000000000000000000000110072674642500216510ustar 00000000000000"\\node" kdl-4.6.0/tests/test_cases/expected_kdl/raw_node_type.kdl000064400000000000000000000000130072674642500217140ustar 00000000000000(type)node kdl-4.6.0/tests/test_cases/expected_kdl/raw_prop_type.kdl000064400000000000000000000000240072674642500217510ustar 00000000000000node key=(type)true kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_arg.kdl000064400000000000000000000001140072674642500220670ustar 00000000000000node_1 "arg\\n" node_2 "\"arg\\n\"and stuff" node_3 "#\"arg\\n\"#and stuff" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_backslash.kdl000064400000000000000000000000130072674642500232470ustar 00000000000000node "\\n" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_hash_no_esc.kdl000064400000000000000000000000110072674642500235630ustar 00000000000000node "#" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_just_backslash.kdl000064400000000000000000000000120072674642500243130ustar 00000000000000node "\\" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_just_quote.kdl000064400000000000000000000000120072674642500235150ustar 00000000000000node "\"" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_multiple_hash.kdl000064400000000000000000000000170072674642500241560ustar 00000000000000node "\"#\"##" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_newline.kdl000064400000000000000000000000300072674642500227540ustar 00000000000000node "\nhello\nworld\n" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_prop.kdl000064400000000000000000000001110072674642500222730ustar 00000000000000node_1 prop="arg\\n" node_2 prop="\"arg\"\\n" node_3 prop="#\"arg\"#\\n" kdl-4.6.0/tests/test_cases/expected_kdl/raw_string_quote.kdl000064400000000000000000000000140072674642500224520ustar 00000000000000node "a\"b" kdl-4.6.0/tests/test_cases/expected_kdl/repeated_arg.kdl000064400000000000000000000000210072674642500214760ustar 00000000000000node "arg" "arg" kdl-4.6.0/tests/test_cases/expected_kdl/repeated_prop.kdl000064400000000000000000000000150072674642500217100ustar 00000000000000node prop=11 kdl-4.6.0/tests/test_cases/expected_kdl/same_args.kdl000064400000000000000000000000230072674642500210170ustar 00000000000000node "whee" "whee" kdl-4.6.0/tests/test_cases/expected_kdl/same_name_nodes.kdl000064400000000000000000000000120072674642500221710ustar 00000000000000node node kdl-4.6.0/tests/test_cases/expected_kdl/semicolon_after_child.kdl000064400000000000000000000000270072674642500233760ustar 00000000000000node { childnode } kdl-4.6.0/tests/test_cases/expected_kdl/semicolon_in_child.kdl000064400000000000000000000000240072674642500227000ustar 00000000000000node1 { node2 } kdl-4.6.0/tests/test_cases/expected_kdl/semicolon_separated.kdl000064400000000000000000000000140072674642500230760ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/expected_kdl/semicolon_separated_nodes.kdl000064400000000000000000000000140072674642500242660ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/expected_kdl/semicolon_terminated.kdl000064400000000000000000000000060072674642500232630ustar 00000000000000node1 kdl-4.6.0/tests/test_cases/expected_kdl/single_arg.kdl000064400000000000000000000000130072674642500211670ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/single_prop.kdl000064400000000000000000000000200072674642500213740ustar 00000000000000node prop="val" kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_arg_after_newline_esc.kdl000064400000000000000000000000140072674642500254150ustar 00000000000000node "arg2" kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_arg_before_newline_esc.kdl000064400000000000000000000000050072674642500255560ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_child.kdl000064400000000000000000000000050072674642500221730ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_empty_child.kdl000064400000000000000000000000050072674642500234110ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_full_node.kdl000064400000000000000000000000010072674642500230530ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_in_slashdash.kdl000064400000000000000000000000060072674642500235510ustar 00000000000000node2 kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_negative_number.kdl000064400000000000000000000000110072674642500242570ustar 00000000000000node 2.0 kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_node_in_child.kdl000064400000000000000000000000060072674642500236670ustar 00000000000000node1 kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_node_with_child.kdl000064400000000000000000000000010072674642500242270ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_only_node.kdl000064400000000000000000000000010072674642500230720ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_only_node_with_space.kdl000064400000000000000000000000010072674642500253000ustar 00000000000000 kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_prop.kdl000064400000000000000000000000130072674642500220670ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_raw_prop_key.kdl000064400000000000000000000000050072674642500236110ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/slashdash_repeated_prop.kdl000064400000000000000000000000230072674642500237410ustar 00000000000000node arg="correct" kdl-4.6.0/tests/test_cases/expected_kdl/string_arg.kdl000064400000000000000000000000130072674642500212140ustar 00000000000000node "arg" kdl-4.6.0/tests/test_cases/expected_kdl/string_prop.kdl000064400000000000000000000000200072674642500214210ustar 00000000000000node prop="val" kdl-4.6.0/tests/test_cases/expected_kdl/tab_space.kdl000064400000000000000000000000050072674642500207770ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/trailing_crlf.kdl000064400000000000000000000000050072674642500216750ustar 00000000000000node kdl-4.6.0/tests/test_cases/expected_kdl/trailing_underscore_hex.kdl000064400000000000000000000000150072674642500237650ustar 00000000000000node 1194684 kdl-4.6.0/tests/test_cases/expected_kdl/trailing_underscore_octal.kdl000064400000000000000000000000100072674642500242760ustar 00000000000000node 83 kdl-4.6.0/tests/test_cases/expected_kdl/true_prefix_in_bare_id.kdl000064400000000000000000000000100072674642500235410ustar 00000000000000true_id kdl-4.6.0/tests/test_cases/expected_kdl/true_prefix_in_prop_key.kdl000064400000000000000000000000170072674642500240130ustar 00000000000000node true_id=1 kdl-4.6.0/tests/test_cases/expected_kdl/two_nodes.kdl000064400000000000000000000000140072674642500210570ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/expected_kdl/underscore_in_float.kdl000064400000000000000000000000120072674642500231000ustar 00000000000000node 11.0 kdl-4.6.0/tests/test_cases/expected_kdl/underscore_in_fraction.kdl000064400000000000000000000000120072674642500236000ustar 00000000000000node 1.02 kdl-4.6.0/tests/test_cases/expected_kdl/underscore_in_int.kdl000064400000000000000000000000100072674642500225630ustar 00000000000000node 10 kdl-4.6.0/tests/test_cases/expected_kdl/underscore_in_octal.kdl000064400000000000000000000000140072674642500230770ustar 00000000000000node 342391 kdl-4.6.0/tests/test_cases/expected_kdl/unusual_bare_id_chars_in_quoted_id.kdl000064400000000000000000000000360072674642500261260ustar 00000000000000foo123~!@#$%^&*.:'|?+ "weeee" kdl-4.6.0/tests/test_cases/expected_kdl/unusual_chars_in_bare_id.kdl000064400000000000000000000000360072674642500240710ustar 00000000000000foo123~!@#$%^&*.:'|?+ "weeee" kdl-4.6.0/tests/test_cases/expected_kdl/zero_arg.kdl000064400000000000000000000000070072674642500206700ustar 00000000000000node 0 kdl-4.6.0/tests/test_cases/expected_kdl/zero_float.kdl000064400000000000000000000000110072674642500212170ustar 00000000000000node 0.0 kdl-4.6.0/tests/test_cases/expected_kdl/zero_int.kdl000064400000000000000000000000070072674642500207110ustar 00000000000000node 0 kdl-4.6.0/tests/test_cases/input/all_escapes.kdl000064400000000000000000000000300072674642500200330ustar 00000000000000node "\"\\\/\b\f\n\r\t" kdl-4.6.0/tests/test_cases/input/all_node_fields.kdl000064400000000000000000000000510072674642500206660ustar 00000000000000node "arg" prop="val" { inner_node } kdl-4.6.0/tests/test_cases/input/arg_and_prop_same_name.kdl000064400000000000000000000000240072674642500222230ustar 00000000000000node "arg" arg="val"kdl-4.6.0/tests/test_cases/input/arg_false_type.kdl000064400000000000000000000000210072674642500205440ustar 00000000000000node (type)false kdl-4.6.0/tests/test_cases/input/arg_float_type.kdl000064400000000000000000000000160072674642500205630ustar 00000000000000node (type)2.5kdl-4.6.0/tests/test_cases/input/arg_hex_type.kdl000064400000000000000000000000200072674642500202350ustar 00000000000000node (type)0x10 kdl-4.6.0/tests/test_cases/input/arg_null_type.kdl000064400000000000000000000000200072674642500204230ustar 00000000000000node (type)null kdl-4.6.0/tests/test_cases/input/arg_raw_string_type.kdl000064400000000000000000000000210072674642500216310ustar 00000000000000node (type)"str" kdl-4.6.0/tests/test_cases/input/arg_string_type.kdl000064400000000000000000000000200072674642500207570ustar 00000000000000node (type)"str"kdl-4.6.0/tests/test_cases/input/arg_true_type.kdl000064400000000000000000000000200072674642500204300ustar 00000000000000node (type)true kdl-4.6.0/tests/test_cases/input/arg_type.kdl000064400000000000000000000000210072674642500173720ustar 00000000000000node (type)"arg" kdl-4.6.0/tests/test_cases/input/arg_zero_type.kdl000064400000000000000000000000150072674642500204340ustar 00000000000000node (type)0 kdl-4.6.0/tests/test_cases/input/asterisk_in_block_comment.kdl000064400000000000000000000000140072674642500227710ustar 00000000000000node /* * */kdl-4.6.0/tests/test_cases/input/backslash_in_bare_id.kdl000064400000000000000000000000230072674642500216500ustar 00000000000000foo123\bar "weeee" kdl-4.6.0/tests/test_cases/input/bare_arg.kdl000064400000000000000000000000060072674642500173250ustar 00000000000000node akdl-4.6.0/tests/test_cases/input/bare_emoji.kdl000064400000000000000000000000160072674642500176600ustar 00000000000000😁 "happy!" kdl-4.6.0/tests/test_cases/input/binary.kdl000064400000000000000000000000110072674642500170430ustar 00000000000000node 0b10kdl-4.6.0/tests/test_cases/input/binary_trailing_underscore.kdl000064400000000000000000000000120072674642500231660ustar 00000000000000node 0b10_kdl-4.6.0/tests/test_cases/input/binary_underscore.kdl000064400000000000000000000000130072674642500212760ustar 00000000000000node 0b1_0 kdl-4.6.0/tests/test_cases/input/blank_arg_type.kdl000064400000000000000000000000130072674642500205420ustar 00000000000000node ("")10kdl-4.6.0/tests/test_cases/input/blank_node_type.kdl000064400000000000000000000000110072674642500207140ustar 00000000000000("")node kdl-4.6.0/tests/test_cases/input/blank_prop_type.kdl000064400000000000000000000000210072674642500207500ustar 00000000000000node key=("")truekdl-4.6.0/tests/test_cases/input/block_comment.kdl000064400000000000000000000000300072674642500203740ustar 00000000000000node /* comment */ "arg"kdl-4.6.0/tests/test_cases/input/block_comment_after_node.kdl000064400000000000000000000000250072674642500225660ustar 00000000000000node /* hey */ "arg" kdl-4.6.0/tests/test_cases/input/block_comment_before_node.kdl000064400000000000000000000000160072674642500227270ustar 00000000000000/* hey */ nodekdl-4.6.0/tests/test_cases/input/block_comment_before_node_no_space.kdl000064400000000000000000000000150072674642500245750ustar 00000000000000/* hey*/node kdl-4.6.0/tests/test_cases/input/block_comment_newline.kdl000064400000000000000000000000120072674642500221150ustar 00000000000000/* hey */ kdl-4.6.0/tests/test_cases/input/boolean_arg.kdl000064400000000000000000000000170072674642500200350ustar 00000000000000node false truekdl-4.6.0/tests/test_cases/input/boolean_prop.kdl000064400000000000000000000000330072674642500202420ustar 00000000000000node prop1=true prop2=falsekdl-4.6.0/tests/test_cases/input/brackets_in_bare_id.kdl000064400000000000000000000000270072674642500215170ustar 00000000000000foo123{bar}foo "weeee" kdl-4.6.0/tests/test_cases/input/chevrons_in_bare_id.kdl000064400000000000000000000000270072674642500215500ustar 00000000000000foo123foo "weeee" kdl-4.6.0/tests/test_cases/input/comma_in_bare_id.kdl000064400000000000000000000000230072674642500210110ustar 00000000000000foo123,bar "weeee" kdl-4.6.0/tests/test_cases/input/comment_after_arg_type.kdl000064400000000000000000000000250072674642500223010ustar 00000000000000node (type)/*huh*/10 kdl-4.6.0/tests/test_cases/input/comment_after_node_type.kdl000064400000000000000000000000220072674642500224520ustar 00000000000000(type)/*huh*/node kdl-4.6.0/tests/test_cases/input/comment_after_prop_type.kdl000064400000000000000000000000310072674642500225050ustar 00000000000000node key=(type)/*huh*/10 kdl-4.6.0/tests/test_cases/input/comment_in_arg_type.kdl000064400000000000000000000000250072674642500216060ustar 00000000000000node (type/*huh*/)10 kdl-4.6.0/tests/test_cases/input/comment_in_node_type.kdl000064400000000000000000000000220072674642500217570ustar 00000000000000(type/*huh*/)node kdl-4.6.0/tests/test_cases/input/comment_in_prop_type.kdl000064400000000000000000000000310072674642500220120ustar 00000000000000node key=(type/*huh*/)10 kdl-4.6.0/tests/test_cases/input/commented_arg.kdl000064400000000000000000000000250072674642500203700ustar 00000000000000node /- "arg1" "arg2"kdl-4.6.0/tests/test_cases/input/commented_child.kdl000064400000000000000000000000420072674642500207010ustar 00000000000000node "arg" /- { inner_node } kdl-4.6.0/tests/test_cases/input/commented_line.kdl000064400000000000000000000000210072674642500205420ustar 00000000000000// node_1 node_2 kdl-4.6.0/tests/test_cases/input/commented_node.kdl000064400000000000000000000000210072674642500205400ustar 00000000000000/- node_1 node_2 kdl-4.6.0/tests/test_cases/input/commented_prop.kdl000064400000000000000000000000300072674642500205730ustar 00000000000000node /- prop="val" "arg"kdl-4.6.0/tests/test_cases/input/crlf_between_nodes.kdl000064400000000000000000000000140072674642500214110ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/input/dash_dash.kdl000064400000000000000000000000070072674642500175020ustar 00000000000000node --kdl-4.6.0/tests/test_cases/input/dot_but_no_fraction.kdl000064400000000000000000000000070072674642500216050ustar 00000000000000node 1.kdl-4.6.0/tests/test_cases/input/dot_but_no_fraction_before_exponent.kdl000064400000000000000000000000110072674642500250420ustar 00000000000000node 1.e7kdl-4.6.0/tests/test_cases/input/dot_in_exponent.kdl000064400000000000000000000000120072674642500207540ustar 00000000000000node 1.0.0kdl-4.6.0/tests/test_cases/input/dot_zero.kdl000064400000000000000000000000070072674642500174110ustar 00000000000000node .0kdl-4.6.0/tests/test_cases/input/emoji.kdl000064400000000000000000000000140072674642500166650ustar 00000000000000node "😀" kdl-4.6.0/tests/test_cases/input/empty.kdl000064400000000000000000000000000072674642500167130ustar 00000000000000kdl-4.6.0/tests/test_cases/input/empty_arg_type.kdl000064400000000000000000000000120072674642500206100ustar 00000000000000node ()10 kdl-4.6.0/tests/test_cases/input/empty_child.kdl000064400000000000000000000000110072674642500200600ustar 00000000000000node { } kdl-4.6.0/tests/test_cases/input/empty_child_different_lines.kdl000064400000000000000000000000110072674642500233000ustar 00000000000000node { } kdl-4.6.0/tests/test_cases/input/empty_child_same_line.kdl000064400000000000000000000000070072674642500221010ustar 00000000000000node {}kdl-4.6.0/tests/test_cases/input/empty_child_whitespace.kdl000064400000000000000000000000170072674642500223020ustar 00000000000000node { } kdl-4.6.0/tests/test_cases/input/empty_node_type.kdl000064400000000000000000000000070072674642500207700ustar 00000000000000()node kdl-4.6.0/tests/test_cases/input/empty_prop_type.kdl000064400000000000000000000000210072674642500210170ustar 00000000000000node key=()false kdl-4.6.0/tests/test_cases/input/empty_quoted_node_id.kdl000064400000000000000000000000100072674642500217560ustar 00000000000000"" "arg"kdl-4.6.0/tests/test_cases/input/empty_quoted_prop_key.kdl000064400000000000000000000000200072674642500222060ustar 00000000000000node ""="empty" kdl-4.6.0/tests/test_cases/input/empty_string_arg.kdl000064400000000000000000000000100072674642500211330ustar 00000000000000node "" kdl-4.6.0/tests/test_cases/input/esc_newline_in_string.kdl000064400000000000000000000000230072674642500221310ustar 00000000000000node "hello\nworld"kdl-4.6.0/tests/test_cases/input/esc_unicode_in_string.kdl000064400000000000000000000000300072674642500221140ustar 00000000000000node "hello\u{0a}world" kdl-4.6.0/tests/test_cases/input/escline.kdl000064400000000000000000000000210072674642500172020ustar 00000000000000node \ "arg" kdl-4.6.0/tests/test_cases/input/escline_comment_node.kdl000064400000000000000000000000310072674642500217320ustar 00000000000000node1 \// hey node2 kdl-4.6.0/tests/test_cases/input/escline_line_comment.kdl000064400000000000000000000000660072674642500217440ustar 00000000000000node \ // comment "arg" \// comment "arg2 " kdl-4.6.0/tests/test_cases/input/escline_node.kdl000064400000000000000000000000140072674642500202110ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/input/false_prefix_in_bare_id.kdl000064400000000000000000000000110072674642500223610ustar 00000000000000false_id kdl-4.6.0/tests/test_cases/input/false_prefix_in_prop_key.kdl000064400000000000000000000000200072674642500226240ustar 00000000000000node false_id=1 kdl-4.6.0/tests/test_cases/input/false_prop_key.kdl000064400000000000000000000000150072674642500205650ustar 00000000000000node false=1 kdl-4.6.0/tests/test_cases/input/hex.kdl000064400000000000000000000000300072674642500163440ustar 00000000000000node 0x1234567890abcdef kdl-4.6.0/tests/test_cases/input/hex_int.kdl000064400000000000000000000000300072674642500172160ustar 00000000000000node 0x1234567890ABCDEF kdl-4.6.0/tests/test_cases/input/hex_int_underscores.kdl000064400000000000000000000000230072674642500216340ustar 00000000000000node 0xABC_def_0123kdl-4.6.0/tests/test_cases/input/hex_leading_zero.kdl000064400000000000000000000000110072674642500210650ustar 00000000000000node 0x01kdl-4.6.0/tests/test_cases/input/illegal_char_in_binary.kdl000064400000000000000000000000130072674642500222210ustar 00000000000000node 0bx01 kdl-4.6.0/tests/test_cases/input/illegal_char_in_hex.kdl000064400000000000000000000000140072674642500215220ustar 00000000000000node 0x10g10kdl-4.6.0/tests/test_cases/input/illegal_char_in_octal.kdl000064400000000000000000000000140072674642500220400ustar 00000000000000node 0o45678kdl-4.6.0/tests/test_cases/input/int_multiple_underscore.kdl000064400000000000000000000000140072674642500225200ustar 00000000000000node 1_2_3_4kdl-4.6.0/tests/test_cases/input/just_block_comment.kdl000064400000000000000000000000110072674642500214400ustar 00000000000000/* hey */kdl-4.6.0/tests/test_cases/input/just_child.kdl000064400000000000000000000000300072674642500177100ustar 00000000000000node { inner_node } kdl-4.6.0/tests/test_cases/input/just_newline.kdl000064400000000000000000000000010072674642500202640ustar 00000000000000 kdl-4.6.0/tests/test_cases/input/just_node_id.kdl000064400000000000000000000000040072674642500202270ustar 00000000000000nodekdl-4.6.0/tests/test_cases/input/just_space.kdl000064400000000000000000000000010072674642500177160ustar 00000000000000 kdl-4.6.0/tests/test_cases/input/just_space_in_arg_type.kdl000064400000000000000000000000160072674642500223040ustar 00000000000000node ( )false kdl-4.6.0/tests/test_cases/input/just_space_in_node_type.kdl000064400000000000000000000000100072674642500224520ustar 00000000000000( )node kdl-4.6.0/tests/test_cases/input/just_space_in_prop_type.kdl000064400000000000000000000000200072674642500225060ustar 00000000000000node key=()0x10 kdl-4.6.0/tests/test_cases/input/just_type_no_arg.kdl000064400000000000000000000000140072674642500211350ustar 00000000000000node (type) kdl-4.6.0/tests/test_cases/input/just_type_no_node_id.kdl000064400000000000000000000000070072674642500217670ustar 00000000000000(type) kdl-4.6.0/tests/test_cases/input/just_type_no_prop.kdl000064400000000000000000000000200072674642500213410ustar 00000000000000node key=(type) kdl-4.6.0/tests/test_cases/input/leading_newline.kdl000064400000000000000000000000060072674642500207070ustar 00000000000000 node kdl-4.6.0/tests/test_cases/input/leading_zero_binary.kdl000064400000000000000000000000120072674642500215660ustar 00000000000000node 0b01 kdl-4.6.0/tests/test_cases/input/leading_zero_int.kdl000064400000000000000000000000110072674642500210730ustar 00000000000000node 011 kdl-4.6.0/tests/test_cases/input/leading_zero_oct.kdl000064400000000000000000000000120072674642500210670ustar 00000000000000node 0o01 kdl-4.6.0/tests/test_cases/input/multiline_comment.kdl000064400000000000000000000000370072674642500213130ustar 00000000000000node /* some comments */ "arg" kdl-4.6.0/tests/test_cases/input/multiline_nodes.kdl000064400000000000000000000000510072674642500207550ustar 00000000000000node \ "arg1" \// comment "arg2" kdl-4.6.0/tests/test_cases/input/multiline_string.kdl000064400000000000000000000000400072674642500211510ustar 00000000000000node " hey everyone how goes? " kdl-4.6.0/tests/test_cases/input/multiple_dots_in_float.kdl000064400000000000000000000000120072674642500223170ustar 00000000000000node 1.0.0kdl-4.6.0/tests/test_cases/input/multiple_dots_in_float_before_exponent.kdl000064400000000000000000000000140072674642500255630ustar 00000000000000node 1.0.0e7kdl-4.6.0/tests/test_cases/input/multiple_es_in_float.kdl000064400000000000000000000000170072674642500217620ustar 00000000000000node 1.0E10e10 kdl-4.6.0/tests/test_cases/input/multiple_x_in_hex.kdl000064400000000000000000000000120072674642500212740ustar 00000000000000node 0xx10kdl-4.6.0/tests/test_cases/input/negative_exponent.kdl000064400000000000000000000000140072674642500213040ustar 00000000000000node 1.0e-10kdl-4.6.0/tests/test_cases/input/negative_float.kdl000064400000000000000000000000230072674642500205510ustar 00000000000000node -1.0 key=-10.0kdl-4.6.0/tests/test_cases/input/negative_int.kdl000064400000000000000000000000210072674642500202340ustar 00000000000000node -10 prop=-15kdl-4.6.0/tests/test_cases/input/nested_block_comment.kdl000064400000000000000000000000500072674642500217400ustar 00000000000000node /* hi /* there */ everyone */ "arg"kdl-4.6.0/tests/test_cases/input/nested_children.kdl000064400000000000000000000000510072674642500207150ustar 00000000000000node1 { node2 { node } } kdl-4.6.0/tests/test_cases/input/nested_comments.kdl000064400000000000000000000000330072674642500207520ustar 00000000000000node /*/* nested */*/ "arg"kdl-4.6.0/tests/test_cases/input/nested_multiline_block_comment.kdl000064400000000000000000000000620072674642500240250ustar 00000000000000node /* hey /* how's */ it going */ "arg" kdl-4.6.0/tests/test_cases/input/newline_between_nodes.kdl000064400000000000000000000000140072674642500221240ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/input/newlines_in_block_comment.kdl000064400000000000000000000000630072674642500227740ustar 00000000000000node /* hey so I was thinking about newts */ "arg" kdl-4.6.0/tests/test_cases/input/no_decimal_exponent.kdl000064400000000000000000000000110072674642500215710ustar 00000000000000node 1e10kdl-4.6.0/tests/test_cases/input/no_digits_in_hex.kdl000064400000000000000000000000070072674642500210750ustar 00000000000000node 0xkdl-4.6.0/tests/test_cases/input/node_false.kdl000064400000000000000000000000130072674642500176600ustar 00000000000000node false kdl-4.6.0/tests/test_cases/input/node_true.kdl000064400000000000000000000000120072674642500175440ustar 00000000000000node true kdl-4.6.0/tests/test_cases/input/node_type.kdl000064400000000000000000000000120072674642500175460ustar 00000000000000(type)nodekdl-4.6.0/tests/test_cases/input/null_arg.kdl000064400000000000000000000000110072674642500173620ustar 00000000000000node nullkdl-4.6.0/tests/test_cases/input/null_prefix_in_bare_id.kdl000064400000000000000000000000100072674642500222400ustar 00000000000000null_id kdl-4.6.0/tests/test_cases/input/null_prefix_in_prop_key.kdl000064400000000000000000000000170072674642500225120ustar 00000000000000node null_id=1 kdl-4.6.0/tests/test_cases/input/null_prop.kdl000064400000000000000000000000160072674642500175760ustar 00000000000000node prop=nullkdl-4.6.0/tests/test_cases/input/null_prop_key.kdl000064400000000000000000000000140072674642500204440ustar 00000000000000node null=1 kdl-4.6.0/tests/test_cases/input/numeric_arg.kdl000064400000000000000000000000110072674642500200520ustar 00000000000000node 15.7kdl-4.6.0/tests/test_cases/input/numeric_prop.kdl000064400000000000000000000000160072674642500202660ustar 00000000000000node prop=10.0kdl-4.6.0/tests/test_cases/input/octal.kdl000064400000000000000000000000170072674642500166670ustar 00000000000000node 0o76543210kdl-4.6.0/tests/test_cases/input/only_cr.kdl000064400000000000000000000000020072674642500172240ustar 00000000000000 kdl-4.6.0/tests/test_cases/input/only_line_comment.kdl000064400000000000000000000000050072674642500212740ustar 00000000000000// hikdl-4.6.0/tests/test_cases/input/only_line_comment_crlf.kdl000064400000000000000000000000130072674642500223010ustar 00000000000000// comment kdl-4.6.0/tests/test_cases/input/only_line_comment_newline.kdl000064400000000000000000000000110072674642500230120ustar 00000000000000// hiiii kdl-4.6.0/tests/test_cases/input/parens_in_bare_id.kdl000064400000000000000000000000270072674642500212110ustar 00000000000000foo123(bar)foo "weeee" kdl-4.6.0/tests/test_cases/input/parse_all_arg_types.kdl000064400000000000000000000001070072674642500216040ustar 00000000000000node 1 1.0 1.0e10 1.0e-10 0x01 0o07 0b10 "arg" r"arg\\" true false nullkdl-4.6.0/tests/test_cases/input/positive_exponent.kdl000064400000000000000000000000140072674642500213440ustar 00000000000000node 1.0e+10kdl-4.6.0/tests/test_cases/input/positive_int.kdl000064400000000000000000000000100072674642500202720ustar 00000000000000node +10kdl-4.6.0/tests/test_cases/input/preserve_duplicate_nodes.kdl000064400000000000000000000000120072674642500226350ustar 00000000000000node node kdl-4.6.0/tests/test_cases/input/preserve_node_order.kdl000064400000000000000000000000220072674642500216140ustar 00000000000000node2 node5 node1 kdl-4.6.0/tests/test_cases/input/prop_false_type.kdl000064400000000000000000000000250072674642500207570ustar 00000000000000node key=(type)false kdl-4.6.0/tests/test_cases/input/prop_float_type.kdl000064400000000000000000000000260072674642500207730ustar 00000000000000node key=(type)2.5E10 kdl-4.6.0/tests/test_cases/input/prop_hex_type.kdl000064400000000000000000000000240072674642500204500ustar 00000000000000node key=(type)0x10 kdl-4.6.0/tests/test_cases/input/prop_null_type.kdl000064400000000000000000000000240072674642500206360ustar 00000000000000node key=(type)null kdl-4.6.0/tests/test_cases/input/prop_raw_string_type.kdl000064400000000000000000000000260072674642500220450ustar 00000000000000node key=(type)r"str" kdl-4.6.0/tests/test_cases/input/prop_string_type.kdl000064400000000000000000000000250072674642500211730ustar 00000000000000node key=(type)"str" kdl-4.6.0/tests/test_cases/input/prop_true_type.kdl000064400000000000000000000000240072674642500206430ustar 00000000000000node key=(type)true kdl-4.6.0/tests/test_cases/input/prop_type.kdl000064400000000000000000000000230072674642500176030ustar 00000000000000node key=(type)truekdl-4.6.0/tests/test_cases/input/prop_zero_type.kdl000064400000000000000000000000210072674642500206400ustar 00000000000000node key=(type)0 kdl-4.6.0/tests/test_cases/input/question_mark_at_start_of_int.kdl000064400000000000000000000000100072674642500236760ustar 00000000000000node ?10kdl-4.6.0/tests/test_cases/input/question_mark_before_number.kdl000064400000000000000000000000100072674642500233310ustar 00000000000000node ?15kdl-4.6.0/tests/test_cases/input/quote_in_bare_id.kdl000064400000000000000000000000230072674642500210520ustar 00000000000000foo123"bar "weeee" kdl-4.6.0/tests/test_cases/input/quoted_arg_type.kdl000064400000000000000000000000200072674642500207520ustar 00000000000000node ("type/")10kdl-4.6.0/tests/test_cases/input/quoted_node_name.kdl000064400000000000000000000000070072674642500210720ustar 00000000000000"0node"kdl-4.6.0/tests/test_cases/input/quoted_node_type.kdl000064400000000000000000000000160072674642500211330ustar 00000000000000("type/")node kdl-4.6.0/tests/test_cases/input/quoted_numeric.kdl000064400000000000000000000000200072674642500206020ustar 00000000000000node prop="10.0"kdl-4.6.0/tests/test_cases/input/quoted_prop_name.kdl000064400000000000000000000000220072674642500211220ustar 00000000000000node "0prop"="val"kdl-4.6.0/tests/test_cases/input/quoted_prop_type.kdl000064400000000000000000000000270072674642500211700ustar 00000000000000node key=("type/")true kdl-4.6.0/tests/test_cases/input/r_node.kdl000064400000000000000000000000100072674642500170240ustar 00000000000000r "arg" kdl-4.6.0/tests/test_cases/input/raw_arg_type.kdl000064400000000000000000000000170072674642500202500ustar 00000000000000node (type)truekdl-4.6.0/tests/test_cases/input/raw_node_name.kdl000064400000000000000000000000100072674642500203540ustar 00000000000000r"\node"kdl-4.6.0/tests/test_cases/input/raw_node_type.kdl000064400000000000000000000000120072674642500204170ustar 00000000000000(type)nodekdl-4.6.0/tests/test_cases/input/raw_prop_type.kdl000064400000000000000000000000230072674642500204540ustar 00000000000000node key=(type)truekdl-4.6.0/tests/test_cases/input/raw_string_arg.kdl000064400000000000000000000001160072674642500205750ustar 00000000000000node_1 r"arg\n" node_2 r#""arg\n"and stuff"# node_3 r##"#"arg\n"#and stuff"## kdl-4.6.0/tests/test_cases/input/raw_string_backslash.kdl000064400000000000000000000000130072674642500217530ustar 00000000000000node r"\n" kdl-4.6.0/tests/test_cases/input/raw_string_hash_no_esc.kdl000064400000000000000000000000120072674642500222700ustar 00000000000000node r"#" kdl-4.6.0/tests/test_cases/input/raw_string_just_backslash.kdl000064400000000000000000000000120072674642500230170ustar 00000000000000node r"\" kdl-4.6.0/tests/test_cases/input/raw_string_just_quote.kdl000064400000000000000000000000140072674642500222230ustar 00000000000000node r#"""# kdl-4.6.0/tests/test_cases/input/raw_string_multiple_hash.kdl000064400000000000000000000000240072674642500226600ustar 00000000000000node r###""#"##"### kdl-4.6.0/tests/test_cases/input/raw_string_newline.kdl000064400000000000000000000000260072674642500214650ustar 00000000000000node r" hello world " kdl-4.6.0/tests/test_cases/input/raw_string_prop.kdl000064400000000000000000000001130072674642500210010ustar 00000000000000node_1 prop=r"arg\n" node_2 prop=r#""arg"\n"# node_3 prop=r##"#"arg"#\n"## kdl-4.6.0/tests/test_cases/input/raw_string_quote.kdl000064400000000000000000000000150072674642500211570ustar 00000000000000node r#"a"b"#kdl-4.6.0/tests/test_cases/input/repeated_arg.kdl000064400000000000000000000000200072674642500202010ustar 00000000000000node "arg" "arg"kdl-4.6.0/tests/test_cases/input/repeated_prop.kdl000064400000000000000000000000240072674642500204140ustar 00000000000000node prop=10 prop=11kdl-4.6.0/tests/test_cases/input/same_args.kdl000064400000000000000000000000220072674642500175220ustar 00000000000000node "whee" "whee"kdl-4.6.0/tests/test_cases/input/same_name_nodes.kdl000064400000000000000000000000120072674642500206750ustar 00000000000000node node kdl-4.6.0/tests/test_cases/input/sci_notation_large.kdl000064400000000000000000000000240072674642500214260ustar 00000000000000node prop=1.23E+1000kdl-4.6.0/tests/test_cases/input/sci_notation_small.kdl000064400000000000000000000000240072674642500214440ustar 00000000000000node prop=1.23E-1000kdl-4.6.0/tests/test_cases/input/semicolon_after_child.kdl000064400000000000000000000000310072674642500220750ustar 00000000000000node { childnode }; kdl-4.6.0/tests/test_cases/input/semicolon_in_child.kdl000064400000000000000000000000270072674642500214070ustar 00000000000000node1 { node2; } kdl-4.6.0/tests/test_cases/input/semicolon_separated.kdl000064400000000000000000000000130072674642500216010ustar 00000000000000node1;node2kdl-4.6.0/tests/test_cases/input/semicolon_separated_nodes.kdl000064400000000000000000000000160072674642500227740ustar 00000000000000node1; node2; kdl-4.6.0/tests/test_cases/input/semicolon_terminated.kdl000064400000000000000000000000060072674642500217670ustar 00000000000000node1;kdl-4.6.0/tests/test_cases/input/single_arg.kdl000064400000000000000000000000120072674642500176720ustar 00000000000000node "arg"kdl-4.6.0/tests/test_cases/input/single_prop.kdl000064400000000000000000000000170072674642500201060ustar 00000000000000node prop="val"kdl-4.6.0/tests/test_cases/input/slash_in_bare_id.kdl000064400000000000000000000000230072674642500210270ustar 00000000000000foo123/bar "weeee" kdl-4.6.0/tests/test_cases/input/slashdash_arg_after_newline_esc.kdl000064400000000000000000000000330072674642500241220ustar 00000000000000node \ /- "arg" "arg2" kdl-4.6.0/tests/test_cases/input/slashdash_arg_before_newline_esc.kdl000064400000000000000000000000270072674642500242660ustar 00000000000000node /- \ "arg" kdl-4.6.0/tests/test_cases/input/slashdash_child.kdl000064400000000000000000000000260072674642500207020ustar 00000000000000node /- { node2 } kdl-4.6.0/tests/test_cases/input/slashdash_empty_child.kdl000064400000000000000000000000140072674642500221150ustar 00000000000000node /- { } kdl-4.6.0/tests/test_cases/input/slashdash_full_node.kdl000064400000000000000000000000270072674642500215670ustar 00000000000000/- node 1.0 "a" b="b " kdl-4.6.0/tests/test_cases/input/slashdash_in_slashdash.kdl000064400000000000000000000000260072674642500222570ustar 00000000000000/- node1 /- 1.0 node2 kdl-4.6.0/tests/test_cases/input/slashdash_negative_number.kdl000064400000000000000000000000170072674642500227710ustar 00000000000000node /--1.0 2.0kdl-4.6.0/tests/test_cases/input/slashdash_node_in_child.kdl000064400000000000000000000000270072674642500223760ustar 00000000000000node1 { /- node2 } kdl-4.6.0/tests/test_cases/input/slashdash_node_with_child.kdl000064400000000000000000000000250072674642500227410ustar 00000000000000/- node { node2 } kdl-4.6.0/tests/test_cases/input/slashdash_only_node.kdl000064400000000000000000000000070072674642500216040ustar 00000000000000/-node kdl-4.6.0/tests/test_cases/input/slashdash_only_node_with_space.kdl000064400000000000000000000000070072674642500240120ustar 00000000000000/- nodekdl-4.6.0/tests/test_cases/input/slashdash_prop.kdl000064400000000000000000000000320072674642500205740ustar 00000000000000node /- key="value" "arg" kdl-4.6.0/tests/test_cases/input/slashdash_raw_prop_key.kdl000064400000000000000000000000240072674642500223160ustar 00000000000000node /- key="value" kdl-4.6.0/tests/test_cases/input/slashdash_repeated_prop.kdl000064400000000000000000000000420072674642500224460ustar 00000000000000node arg="correct" /- arg="wrong" kdl-4.6.0/tests/test_cases/input/space_after_arg_type.kdl000064400000000000000000000000170072674642500217330ustar 00000000000000node (type) 10 kdl-4.6.0/tests/test_cases/input/space_after_node_type.kdl000064400000000000000000000000140072674642500221040ustar 00000000000000(type) node kdl-4.6.0/tests/test_cases/input/space_after_prop_type.kdl000064400000000000000000000000260072674642500221420ustar 00000000000000node key=(type) false kdl-4.6.0/tests/test_cases/input/space_in_arg_type.kdl000064400000000000000000000000220072674642500212340ustar 00000000000000node (type )false kdl-4.6.0/tests/test_cases/input/space_in_node_type.kdl000064400000000000000000000000140072674642500214110ustar 00000000000000( type)node kdl-4.6.0/tests/test_cases/input/space_in_prop_type.kdl000064400000000000000000000000260072674642500214470ustar 00000000000000node key=(type )false kdl-4.6.0/tests/test_cases/input/square_bracket_in_bare_id.kdl000064400000000000000000000000270072674642500227140ustar 00000000000000foo123[bar]foo "weeee" kdl-4.6.0/tests/test_cases/input/string_arg.kdl000064400000000000000000000000120072674642500177170ustar 00000000000000node "arg"kdl-4.6.0/tests/test_cases/input/string_prop.kdl000064400000000000000000000000170072674642500201330ustar 00000000000000node prop="val"kdl-4.6.0/tests/test_cases/input/tab_space.kdl000064400000000000000000000000050072674642500175030ustar 00000000000000node kdl-4.6.0/tests/test_cases/input/trailing_crlf.kdl000064400000000000000000000000050072674642500204010ustar 00000000000000node kdl-4.6.0/tests/test_cases/input/trailing_underscore_hex.kdl000064400000000000000000000000160072674642500224720ustar 00000000000000node 0x123abc_kdl-4.6.0/tests/test_cases/input/trailing_underscore_octal.kdl000064400000000000000000000000140072674642500230060ustar 00000000000000node 0o123_ kdl-4.6.0/tests/test_cases/input/true_prefix_in_bare_id.kdl000064400000000000000000000000100072674642500222450ustar 00000000000000true_id kdl-4.6.0/tests/test_cases/input/true_prefix_in_prop_key.kdl000064400000000000000000000000170072674642500225170ustar 00000000000000node true_id=1 kdl-4.6.0/tests/test_cases/input/true_prop_key.kdl000064400000000000000000000000140072674642500204510ustar 00000000000000node true=1 kdl-4.6.0/tests/test_cases/input/two_nodes.kdl000064400000000000000000000000140072674642500175630ustar 00000000000000node1 node2 kdl-4.6.0/tests/test_cases/input/type_before_prop_key.kdl000064400000000000000000000000220072674642500217740ustar 00000000000000node (type)key=10 kdl-4.6.0/tests/test_cases/input/unbalanced_raw_hashes.kdl000064400000000000000000000000170072674642500220650ustar 00000000000000node r##"foo"# kdl-4.6.0/tests/test_cases/input/underscore_at_start_of_fraction.kdl000064400000000000000000000000110072674642500242020ustar 00000000000000node 1._7kdl-4.6.0/tests/test_cases/input/underscore_at_start_of_hex.kdl000064400000000000000000000000120072674642500231620ustar 00000000000000node 0x_10kdl-4.6.0/tests/test_cases/input/underscore_at_start_of_int.kdl000064400000000000000000000000100072674642500231660ustar 00000000000000node _15kdl-4.6.0/tests/test_cases/input/underscore_before_number.kdl000064400000000000000000000000110072674642500226220ustar 00000000000000node _15 kdl-4.6.0/tests/test_cases/input/underscore_in_exponent.kdl000064400000000000000000000000170072674642500223440ustar 00000000000000node 1.0e-10_0 kdl-4.6.0/tests/test_cases/input/underscore_in_float.kdl000064400000000000000000000000130072674642500216050ustar 00000000000000node 1_1.0 kdl-4.6.0/tests/test_cases/input/underscore_in_fraction.kdl000064400000000000000000000000120072674642500223040ustar 00000000000000node 1.0_2kdl-4.6.0/tests/test_cases/input/underscore_in_int.kdl000064400000000000000000000000110072674642500212700ustar 00000000000000node 1_0 kdl-4.6.0/tests/test_cases/input/underscore_in_octal.kdl000064400000000000000000000000210072674642500216010ustar 00000000000000node 0o012_3456_7kdl-4.6.0/tests/test_cases/input/unusual_bare_id_chars_in_quoted_id.kdl000064400000000000000000000000370072674642500246330ustar 00000000000000"foo123~!@#$%^&*.:'|?+" "weeee"kdl-4.6.0/tests/test_cases/input/unusual_chars_in_bare_id.kdl000064400000000000000000000000360072674642500225750ustar 00000000000000foo123~!@#$%^&*.:'|?+ "weeee" kdl-4.6.0/tests/test_cases/input/zero_arg.kdl000064400000000000000000000000070072674642500173740ustar 00000000000000node 0 kdl-4.6.0/tests/test_cases/input/zero_float.kdl000064400000000000000000000000110072674642500177230ustar 00000000000000node 0.0 kdl-4.6.0/tests/test_cases/input/zero_int.kdl000064400000000000000000000000070072674642500174150ustar 00000000000000node 0