├── .gitignore ├── .reuse └── dep5 ├── LICENSES ├── CC0-1.0.txt └── MPL-2.0.txt ├── Makefile ├── README.md ├── src └── Language │ ├── TOML.idr │ └── TOML │ ├── ConcreteSyntax.idr │ ├── Lexer.idr │ ├── Parser.idr │ ├── Processing.idr │ ├── Tokens.idr │ └── Value.idr ├── tests.ipkg ├── tests ├── Files.idr ├── Lexer.idr ├── Parser.idr ├── Process.idr ├── Tests.idr └── pass │ └── test.toml └── toml.ipkg /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | # 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | build/* 6 | tests/build/* -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: toml-idr 3 | Upstream-Contact: The toml-idr developers <> 4 | Source: https://github.com/tiatomee/toml-idr 5 | 6 | # Sample paragraph, commented out: 7 | # 8 | # Files: src/* 9 | # Copyright: $YEAR $NAME <$CONTACT> 10 | # License: ... 11 | 12 | Files: tests/pass/* 13 | Copyright: 2021 The toml-idr developers 14 | License: CC0-1.0 -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /LICENSES/MPL-2.0.txt: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" means each individual or legal entity that creates, contributes 6 | to the creation of, or owns Covered Software. 7 | 8 | 1.2. "Contributor Version" means the combination of the Contributions of others 9 | (if any) used by a Contributor and that particular Contributor's Contribution. 10 | 11 | 1.3. "Contribution" means Covered Software of a particular Contributor. 12 | 13 | 1.4. "Covered Software" means Source Code Form to which the initial Contributor 14 | has attached the notice in Exhibit A, the Executable Form of such Source Code 15 | Form, and Modifications of such Source Code Form, in each case including portions 16 | thereof. 17 | 18 | 1.5. "Incompatible With Secondary Licenses" means 19 | 20 | (a) that the initial Contributor has attached the notice described in Exhibit 21 | B to the Covered Software; or 22 | 23 | (b) that the Covered Software was made available under the terms of version 24 | 1.1 or earlier of the License, but not also under the terms of a Secondary 25 | License. 26 | 27 | 1.6. "Executable Form" means any form of the work other than Source Code Form. 28 | 29 | 1.7. "Larger Work" means a work that combines Covered Software with other 30 | material, in a separate file or files, that is not Covered Software. 31 | 32 | 1.8. "License" means this document. 33 | 34 | 1.9. "Licensable" means having the right to grant, to the maximum extent possible, 35 | whether at the time of the initial grant or subsequently, any and all of the 36 | rights conveyed by this License. 37 | 38 | 1.10. "Modifications" means any of the following: 39 | 40 | (a) any file in Source Code Form that results from an addition to, deletion 41 | from, or modification of the contents of Covered Software; or 42 | 43 | (b) any new file in Source Code Form that contains any Covered Software. 44 | 45 | 1.11. "Patent Claims" of a Contributor means any patent claim(s), including 46 | without limitation, method, process, and apparatus claims, in any patent Licensable 47 | by such Contributor that would be infringed, but for the grant of the License, 48 | by the making, using, selling, offering for sale, having made, import, or 49 | transfer of either its Contributions or its Contributor Version. 50 | 51 | 1.12. "Secondary License" means either the GNU General Public License, Version 52 | 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General 53 | Public License, Version 3.0, or any later versions of those licenses. 54 | 55 | 1.13. "Source Code Form" means the form of the work preferred for making modifications. 56 | 57 | 1.14. "You" (or "Your") means an individual or a legal entity exercising rights 58 | under this License. For legal entities, "You" includes any entity that controls, 59 | is controlled by, or is under common control with You. For purposes of this 60 | definition, "control" means (a) the power, direct or indirect, to cause the 61 | direction or management of such entity, whether by contract or otherwise, 62 | or (b) ownership of more than fifty percent (50%) of the outstanding shares 63 | or beneficial ownership of such entity. 64 | 65 | 2. License Grants and Conditions 66 | 67 | 2.1. Grants 68 | Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive 69 | license: 70 | 71 | (a) under intellectual property rights (other than patent or trademark) Licensable 72 | by such Contributor to use, reproduce, make available, modify, display, perform, 73 | distribute, and otherwise exploit its Contributions, either on an unmodified 74 | basis, with Modifications, or as part of a Larger Work; and 75 | 76 | (b) under Patent Claims of such Contributor to make, use, sell, offer for 77 | sale, have made, import, and otherwise transfer either its Contributions or 78 | its Contributor Version. 79 | 80 | 2.2. Effective Date 81 | The licenses granted in Section 2.1 with respect to any Contribution become 82 | effective for each Contribution on the date the Contributor first distributes 83 | such Contribution. 84 | 85 | 2.3. Limitations on Grant Scope 86 | The licenses granted in this Section 2 are the only rights granted under this 87 | License. No additional rights or licenses will be implied from the distribution 88 | or licensing of Covered Software under this License. Notwithstanding Section 89 | 2.1(b) above, no patent license is granted by a Contributor: 90 | 91 | (a) for any code that a Contributor has removed from Covered Software; or 92 | 93 | (b) for infringements caused by: (i) Your and any other third party's modifications 94 | of Covered Software, or (ii) the combination of its Contributions with other 95 | software (except as part of its Contributor Version); or 96 | 97 | (c) under Patent Claims infringed by Covered Software in the absence of its 98 | Contributions. 99 | 100 | This License does not grant any rights in the trademarks, service marks, or 101 | logos of any Contributor (except as may be necessary to comply with the notice 102 | requirements in Section 3.4). 103 | 104 | 2.4. Subsequent Licenses 105 | No Contributor makes additional grants as a result of Your choice to distribute 106 | the Covered Software under a subsequent version of this License (see Section 107 | 10.2) or under the terms of a Secondary License (if permitted under the terms 108 | of Section 3.3). 109 | 110 | 2.5. Representation 111 | Each Contributor represents that the Contributor believes its Contributions 112 | are its original creation(s) or it has sufficient rights to grant the rights 113 | to its Contributions conveyed by this License. 114 | 115 | 2.6. Fair Use 116 | This License is not intended to limit any rights You have under applicable 117 | copyright doctrines of fair use, fair dealing, or other equivalents. 118 | 119 | 2.7. Conditions 120 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 121 | Section 2.1. 122 | 123 | 3. Responsibilities 124 | 125 | 3.1. Distribution of Source Form 126 | All distribution of Covered Software in Source Code Form, including any Modifications 127 | that You create or to which You contribute, must be under the terms of this 128 | License. You must inform recipients that the Source Code Form of the Covered 129 | Software is governed by the terms of this License, and how they can obtain 130 | a copy of this License. You may not attempt to alter or restrict the recipients' 131 | rights in the Source Code Form. 132 | 133 | 3.2. Distribution of Executable Form 134 | If You distribute Covered Software in Executable Form then: 135 | 136 | (a) such Covered Software must also be made available in Source Code Form, 137 | as described in Section 3.1, and You must inform recipients of the Executable 138 | Form how they can obtain a copy of such Source Code Form by reasonable means 139 | in a timely manner, at a charge no more than the cost of distribution to the 140 | recipient; and 141 | 142 | (b) You may distribute such Executable Form under the terms of this License, 143 | or sublicense it under different terms, provided that the license for the 144 | Executable Form does not attempt to limit or alter the recipients' rights 145 | in the Source Code Form under this License. 146 | 147 | 3.3. Distribution of a Larger Work 148 | You may create and distribute a Larger Work under terms of Your choice, provided 149 | that You also comply with the requirements of this License for the Covered 150 | Software. If the Larger Work is a combination of Covered Software with a work 151 | governed by one or more Secondary Licenses, and the Covered Software is not 152 | Incompatible With Secondary Licenses, this License permits You to additionally 153 | distribute such Covered Software under the terms of such Secondary License(s), 154 | so that the recipient of the Larger Work may, at their option, further distribute 155 | the Covered Software under the terms of either this License or such Secondary 156 | License(s). 157 | 158 | 3.4. Notices 159 | You may not remove or alter the substance of any license notices (including 160 | copyright notices, patent notices, disclaimers of warranty, or limitations 161 | of liability) contained within the Source Code Form of the Covered Software, 162 | except that You may alter any license notices to the extent required to remedy 163 | known factual inaccuracies. 164 | 165 | 3.5. Application of Additional Terms 166 | You may choose to offer, and to charge a fee for, warranty, support, indemnity 167 | or liability obligations to one or more recipients of Covered Software. However, 168 | You may do so only on Your own behalf, and not on behalf of any Contributor. 169 | You must make it absolutely clear that any such warranty, support, indemnity, 170 | or liability obligation is offered by You alone, and You hereby agree to indemnify 171 | every Contributor for any liability incurred by such Contributor as a result 172 | of warranty, support, indemnity or liability terms You offer. You may include 173 | additional disclaimers of warranty and limitations of liability specific to 174 | any jurisdiction. 175 | 176 | 4. Inability to Comply Due to Statute or Regulation 177 | If it is impossible for You to comply with any of the terms of this License 178 | with respect to some or all of the Covered Software due to statute, judicial 179 | order, or regulation then You must: (a) comply with the terms of this License 180 | to the maximum extent possible; and (b) describe the limitations and the code 181 | they affect. Such description must be placed in a text file included with 182 | all distributions of the Covered Software under this License. Except to the 183 | extent prohibited by statute or regulation, such description must be sufficiently 184 | detailed for a recipient of ordinary skill to be able to understand it. 185 | 186 | 5. Termination 187 | 188 | 5.1. The rights granted under this License will terminate automatically if 189 | You fail to comply with any of its terms. However, if You become compliant, 190 | then the rights granted under this License from a particular Contributor are 191 | reinstated (a) provisionally, unless and until such Contributor explicitly 192 | and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor 193 | fails to notify You of the non-compliance by some reasonable means prior to 194 | 60 days after You have come back into compliance. Moreover, Your grants from 195 | a particular Contributor are reinstated on an ongoing basis if such Contributor 196 | notifies You of the non-compliance by some reasonable means, this is the first 197 | time You have received notice of non-compliance with this License from such 198 | Contributor, and You become compliant prior to 30 days after Your receipt 199 | of the notice. 200 | 201 | 5.2. If You initiate litigation against any entity by asserting a patent infringement 202 | claim (excluding declaratory judgment actions, counter-claims, and cross-claims) 203 | alleging that a Contributor Version directly or indirectly infringes any patent, 204 | then the rights granted to You by any and all Contributors for the Covered 205 | Software under Section 2.1 of this License shall terminate. 206 | 207 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end 208 | user license agreements (excluding distributors and resellers) which have 209 | been validly granted by You or Your distributors under this License prior 210 | to termination shall survive termination. 211 | 212 | 6. Disclaimer of Warranty 213 | Covered Software is provided under this License on an "as is" basis, without 214 | warranty of any kind, either expressed, implied, or statutory, including, 215 | without limitation, warranties that the Covered Software is free of defects, 216 | merchantable, fit for a particular purpose or non-infringing. The entire risk 217 | as to the quality and performance of the Covered Software is with You. Should 218 | any Covered Software prove defective in any respect, You (not any Contributor) 219 | assume the cost of any necessary servicing, repair, or correction. This disclaimer 220 | of warranty constitutes an essential part of this License. No use of any Covered 221 | Software is authorized under this License except under this disclaimer. 222 | 223 | 7. Limitation of Liability 224 | Under no circumstances and under no legal theory, whether tort (including 225 | negligence), contract, or otherwise, shall any Contributor, or anyone who 226 | distributes Covered Software as permitted above, be liable to You for any 227 | direct, indirect, special, incidental, or consequential damages of any character 228 | including, without limitation, damages for lost profits, loss of goodwill, 229 | work stoppage, computer failure or malfunction, or any and all other commercial 230 | damages or losses, even if such party shall have been informed of the possibility 231 | of such damages. This limitation of liability shall not apply to liability 232 | for death or personal injury resulting from such party's negligence to the 233 | extent applicable law prohibits such limitation. Some jurisdictions do not 234 | allow the exclusion or limitation of incidental or consequential damages, 235 | so this exclusion and limitation may not apply to You. 236 | 237 | 8. Litigation 238 | Any litigation relating to this License may be brought only in the courts 239 | of a jurisdiction where the defendant maintains its principal place of business 240 | and such litigation shall be governed by laws of that jurisdiction, without 241 | reference to its conflict-of-law provisions. Nothing in this Section shall 242 | prevent a party's ability to bring cross-claims or counter-claims. 243 | 244 | 9. Miscellaneous 245 | This License represents the complete agreement concerning the subject matter 246 | hereof. If any provision of this License is held to be unenforceable, such 247 | provision shall be reformed only to the extent necessary to make it enforceable. 248 | Any law or regulation which provides that the language of a contract shall 249 | be construed against the drafter shall not be used to construe this License 250 | against a Contributor. 251 | 252 | 10. Versions of the License 253 | 254 | 10.1. New Versions 255 | Mozilla Foundation is the license steward. Except as provided in Section 10.3, 256 | no one other than the license steward has the right to modify or publish new 257 | versions of this License. Each version will be given a distinguishing version 258 | number. 259 | 260 | 10.2. Effect of New Versions 261 | You may distribute the Covered Software under the terms of the version of 262 | the License under which You originally received the Covered Software, or under 263 | the terms of any subsequent version published by the license steward. 264 | 265 | 10.3. Modified Versions 266 | If you create software not governed by this License, and you want to create 267 | a new license for such software, you may create and use a modified version 268 | of this License if you rename the license and remove any references to the 269 | name of the license steward (except to note that such modified license differs 270 | from this License). 271 | 272 | 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses 273 | If You choose to distribute Source Code Form that is Incompatible With Secondary 274 | Licenses under the terms of this version of the License, the notice described 275 | in Exhibit B of this License must be attached. 276 | 277 | Exhibit A - Source Code Form License Notice 278 | 279 | This Source Code Form is subject to the terms of the Mozilla Public License, 280 | v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain 281 | one at http://mozilla.org/MPL/2.0/. 282 | 283 | If it is not possible or desirable to put the notice in a particular file, 284 | then You may include the notice in a location (such as a LICENSE file in a 285 | relevant directory) where a recipient would be likely to look for such a notice. 286 | 287 | You may add additional accurate notices of copyright ownership. 288 | 289 | Exhibit B - "Incompatible With Secondary Licenses" Notice 290 | 291 | This Source Code Form is "Incompatible With Secondary Licenses", as defined 292 | by the Mozilla Public License, v. 2.0. 293 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | # 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | .PHONY: toml 6 | toml: 7 | @printf "Building toml-idr ..." 8 | @output=`idris2 --build toml.ipkg 2>&1` || (printf '\n%s\n' "$$output" && false) 9 | @printf " done!\n" 10 | 11 | .PHONY: install 12 | install: toml 13 | @printf "Installing toml-idr ..." 14 | @output=`idris2 --install toml.ipkg 2>&1` || (printf '\n%s\n' "$$output" && false) 15 | @printf " done!\n" 16 | 17 | .PHONY: tests 18 | tests: install 19 | @printf "Building test package ..." 20 | @output=`idris2 --build tests.ipkg 2>&1` || (printf '\n%s\n' "$$output" && false) 21 | @printf " done!\n" 22 | @echo "Running tests:" 23 | @./build/exec/tests 24 | 25 | .PHONY: clear 26 | clear: 27 | rm build -rf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # `toml-idr` 8 | 9 | A [TOML](https://toml.io/) parser for [Idris 2](https://github.com/idris-lang/Idris2). 10 | 11 | ## State of implementation 12 | 13 | Supported values: 14 | - [x] integers (without `_` separators **TODO**) 15 | - [x] floats (without `_` separators **TODO**) 16 | - [x] strings (only `\"` escape is supported for now **TODO**) 17 | - [ ] multi-line strings 18 | - [ ] literal strings 19 | - [ ] multi-line literal strings 20 | - [x] booleans 21 | - [x] arrays 22 | - [x] inline tables 23 | - [ ] Offset Date-Time 24 | - [ ] Local Date-Time 25 | - [ ] Local Date 26 | - [ ] Local Time 27 | 28 | Arrays of tables (`[[thing]]`) are currently not supported. **Work in progress** 29 | 30 | Since literal strings and not supported yet, they are also not supported in keys. **Work in progress** 31 | 32 | ## Installation 33 | 34 | At least version `0.3.0` of the Idris 2 compiler is required. 35 | 36 | ```sh 37 | idris2 --install toml.ipkg 38 | ``` 39 | 40 | ## Usage 41 | 42 | After installing the package, add `toml` to the `depends` section in the `.ipkg` file. 43 | 44 | To parse a TOML file, the `parseTOML` function in the `Language.TOML` module 45 | can be used. 46 | 47 | Values are represented with the `Value` type. 48 | 49 | A file is represented as one `Table`. A `Table` is a `SortedMap`, so 50 | `lookup`, `insert` and friends will work as usual. 51 | To lookup nested keys (such as `["animal", "type", "name"]`) the `lookupNested` 52 | function can be used. 53 | 54 | ## Development 55 | 56 | To run the tests, run `make tests`. The tests need the 57 | [`tester` package](https://github.com/tiatomee/tester-idr) to be installed 58 | 59 | The command `make clear` will clean the build directory. 60 | 61 | ## License 62 | 63 | All code is licensed under the [MPL-2.0](LICENSES/MPL-2.0.txt). 64 | 65 | All files that are not properly copyrightable are in the public domain, using 66 | the [CC0 license](LICENSES/CC0-1.0.txt). 67 | 68 | This project aims to be [REUSE compliant](https://reuse.software/). -------------------------------------------------------------------------------- /src/Language/TOML.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: MPL-2.0 4 | 5 | module Language.TOML 6 | 7 | 8 | import Data.List 9 | import Data.List1 10 | import Data.SortedMap 11 | 12 | import Text.Bounded 13 | import Text.Token 14 | import Language.TOML.Lexer 15 | import Language.TOML.Parser 16 | import public Language.TOML.Value 17 | import Language.TOML.ConcreteSyntax as C 18 | 19 | 20 | 21 | private 22 | data SectionIdent = SGlobal 23 | | STable CKey 24 | | STableArray CKey 25 | 26 | toPair : Item -> Maybe (CKey,CValue) 27 | toPair (IKeyValue key val) = Just (key,val) 28 | toPair (ITableHeader _) = Nothing 29 | toPair (ITableArray _) = Nothing 30 | 31 | takeWhileJust : (a -> Maybe b) -> List a -> (List b, List a) 32 | takeWhileJust f [] = ([],[]) 33 | takeWhileJust f (x :: xs) = case f x of 34 | Nothing => ([],x :: xs) 35 | Just vb => let (bs,as) = takeWhileJust f xs in (vb :: bs, as) 36 | 37 | 38 | private 39 | sections : List C.Item -> List (SectionIdent, List (CKey, CValue)) 40 | sections xs = loop SGlobal xs 41 | where 42 | loop : SectionIdent -> List C.Item -> List (SectionIdent, List (CKey, CValue)) 43 | loop sec [] = [] 44 | loop sec ((ITableHeader header) :: xs) = loop (STable header) xs 45 | loop sec ((ITableArray header) :: xs) = loop (STableArray header) xs 46 | loop sec xs = 47 | let (kvs, rest) = takeWhileJust toPair xs 48 | in (sec, kvs) :: loop sec rest 49 | 50 | 51 | public export 52 | data Error = ErrDottedIsNotATable Key Value 53 | | LexerError 54 | | ParseError (List String) 55 | | Unimplemented 56 | 57 | 58 | public export 59 | Show Error where 60 | show (ErrDottedIsNotATable x y) = "Dotted key part `" ++ show x ++ "`is not a table" 61 | show LexerError = "Lexer error" 62 | show (ParseError x) = "Parse error: " ++ show x 63 | show Unimplemented = "Unimplemented feature" 64 | 65 | private 66 | keyAtomStr : CKeyAtom -> Key 67 | keyAtomStr (CKBare x) = x 68 | keyAtomStr (CKQuoted x) = x 69 | 70 | private 71 | keyParts : CKey -> List1 Key 72 | keyParts (CKAtom x) = keyAtomStr x ::: [] 73 | keyParts (CKDotted x) = map keyAtomStr x 74 | 75 | public export 76 | Eq CKeyAtom where 77 | x == y = keyAtomStr x == keyAtomStr y 78 | 79 | public export 80 | Eq CKey where 81 | x == y = keyParts x == keyParts y 82 | 83 | private 84 | tableSetWithParts : (t : Table) -> (path : List1 Key) -> (val : Value) -> Either Error Table 85 | tableSetWithParts t (head ::: []) val = pure $ insert head val t 86 | tableSetWithParts t (head ::: (x :: xs)) val = do 87 | inner <- case lookup head t of 88 | Nothing => pure empty 89 | Just (VTable t) => pure t 90 | Just v => Left $ ErrDottedIsNotATable head v 91 | 92 | inner' <- tableSetWithParts inner (x ::: xs) val 93 | pure $ insert head (VTable inner') t 94 | 95 | 96 | mutual 97 | 98 | private 99 | cvalToVal : CValue -> Either Error Value 100 | cvalToVal (CVString x) = pure $ VString x 101 | cvalToVal (CVInteger x) = pure $ VInteger x 102 | cvalToVal (CVFloat x) = pure $ VFloat x 103 | cvalToVal (CVBoolean x) = pure $ VBoolean x 104 | cvalToVal (CVArray xs) = map VArray $ for xs cvalToVal 105 | cvalToVal (CVInlineTable xs) = map VTable $ tableFromKVs xs 106 | 107 | private 108 | tableFromKVs : List (CKey, CValue) -> Either Error Table 109 | tableFromKVs xs = loop empty xs 110 | where 111 | loop : Table -> List (CKey, CValue) -> Either Error Table 112 | loop t [] = Right t 113 | loop t ((k, v) :: xs) = do 114 | v' <- cvalToVal v 115 | let parts = keyParts k 116 | t' <- tableSetWithParts t parts v' 117 | loop t' xs 118 | 119 | private 120 | extendFile : (file : Table) -> (sects : List (SectionIdent, List (CKey, CValue))) -> Either Error Table 121 | extendFile file [] = pure file 122 | extendFile file ((SGlobal, kvs) :: rest) = do 123 | tab <- tableFromKVs kvs 124 | extendFile (mergeLeft tab file) rest 125 | extendFile file (((STable key), kvs) :: rest) = do 126 | tab <- tableFromKVs kvs 127 | let kParts = keyParts key 128 | file' <- tableSetWithParts file kParts (VTable tab) 129 | extendFile file' rest 130 | 131 | extendFile file rest@(((STableArray key), kvs) :: _) = do 132 | let (array, rest') = partition 133 | (\(sect, _) => case sect of 134 | (STableArray key') => key == key' 135 | _ => False) 136 | rest 137 | array' <- traverse (map VTable . tableFromKVs) (map snd array) 138 | file' <- tableSetWithParts file (keyParts key) (VArray array') 139 | extendFile file' rest' 140 | 141 | export 142 | parseTOML : (src : String) -> Either Error Table 143 | parseTOML src = do 144 | let Just toks = lexTOML src 145 | | Nothing => Left LexerError 146 | 147 | items <- bimap ParseError id (parseItems toks) 148 | 149 | let sects = sections items 150 | 151 | extendFile empty sects 152 | -------------------------------------------------------------------------------- /src/Language/TOML/ConcreteSyntax.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: MPL-2.0 4 | 5 | module Language.TOML.ConcreteSyntax 6 | 7 | import Data.String 8 | import Data.List 9 | import Data.List1 10 | 11 | public export 12 | data CKeyAtom = CKBare String 13 | | CKQuoted String 14 | 15 | public export 16 | data CKey = CKAtom CKeyAtom 17 | | CKDotted (List1 CKeyAtom) 18 | 19 | public export 20 | data CValue 21 | = CVString String 22 | | CVInteger Integer 23 | | CVFloat Double 24 | | CVBoolean Bool 25 | | CVArray (List CValue) 26 | | CVInlineTable (List (CKey, CValue)) 27 | 28 | 29 | public export 30 | data Item : Type where 31 | IKeyValue : (key : CKey) -> (val : CValue) -> Item 32 | ITableHeader : (header : CKey) -> Item 33 | ITableArray : (header : CKey) -> Item 34 | 35 | 36 | public export 37 | Show CKeyAtom where 38 | show (CKBare x) = x 39 | show (CKQuoted x) = "\"" ++ x ++ "\"" 40 | 41 | public export 42 | Show CKey where 43 | show (CKAtom x) = show x 44 | show (CKDotted x) = fastConcat . intersperse "." . forget $ show <$> x 45 | 46 | public export 47 | Show CValue where 48 | show (CVString x) = show x 49 | show (CVInteger x) = show x 50 | show (CVFloat x) = show x 51 | show (CVBoolean x) = show x 52 | show (CVArray xs) = "[" 53 | ++ fastConcat (intersperse ", " $ map (assert_total show) xs) 54 | ++ "]" 55 | show (CVInlineTable xs) = "{" 56 | ++ fastConcat (intersperse ", " $ map (\(k, v) => show k ++ " = " ++ assert_total show v) xs) 57 | ++ "}" 58 | 59 | public export 60 | Show Item where 61 | show (IKeyValue key val) = "keyval: " ++ show key ++ " = " ++ show val 62 | show (ITableHeader header) = "table: " ++ show header 63 | show (ITableArray header) = "tablearr: " ++ show header -------------------------------------------------------------------------------- /src/Language/TOML/Lexer.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: MPL-2.0 4 | 5 | module Language.TOML.Lexer 6 | 7 | import Text.Lexer 8 | import Text.Token 9 | 10 | import public Language.TOML.Tokens 11 | 12 | %default total 13 | 14 | private 15 | nonZeroDigit : Lexer 16 | nonZeroDigit = range '1' '9' 17 | 18 | private 19 | floatLit : Lexer 20 | floatLit 21 | = let sign = oneOf "+-" 22 | whole = is '0' <|> nonZeroDigit <+> many (opt (is '_') <+> digit) 23 | frac = the Lexer $ is '.' <+> digit <+> many (opt (is '_') <+> digit) 24 | exp = the Lexer $ like 'e' <+> opt (oneOf "+-") <+> digits 25 | constant = exact "nan" <|> exact "inf" in 26 | opt sign <+> ( 27 | whole <+> ((frac <+> opt exp) <|> exp) 28 | <|> constant) 29 | 30 | private 31 | sepIntLit : Lexer 32 | sepIntLit = opt (oneOf "+-") <+> nonZeroDigit <+> many (is '_' <|> digit) 33 | 34 | private 35 | sepBaseLit : (pre : String) -> (digit : Lexer) -> Lexer 36 | sepBaseLit pre digit = 37 | exact pre 38 | <+> digit 39 | <+> many (opt (is '_') <+> digit) 40 | 41 | private 42 | integerLit : Lexer 43 | integerLit = 44 | (sepBaseLit "0x" hexDigit 45 | <|> sepBaseLit "0o" octDigit 46 | <|> sepBaseLit "0b" binDigit 47 | <|> sepIntLit) <+> reject (oneOf ".eE") 48 | 49 | private 50 | bareKey : Lexer 51 | bareKey = some (alphaNum <|> is '_' <|> is '-') 52 | 53 | -- TODO doesn't handle single quoted strings or escapes yet 54 | private 55 | basicStringLit : Lexer 56 | basicStringLit = quote (is '"') (escape (is '\\') any <|> isNot '\\') 57 | 58 | private 59 | tomlTokenMap : TokenMap TOMLToken 60 | tomlTokenMap = toTokenMap $ 61 | [ 62 | (newline, TTPunct NewLine), 63 | (lineComment (is '#'), TTIgnored), 64 | (spaces, TTIgnored), 65 | (is ',', TTPunct Comma), 66 | (is '.', TTPunct Dot), 67 | (is '=', TTPunct Equal), 68 | (is '[', TTPunct $ Square Open), 69 | (is ']', TTPunct $ Square Close), 70 | (is '{', TTPunct $ Curly Open), 71 | (is '}', TTPunct $ Curly Close), 72 | (exact strTrue <|> exact strFalse, TTBoolean), 73 | (integerLit, TTInt), 74 | (floatLit, TTFloat), 75 | -- TODO: other string types 76 | (Language.TOML.Lexer.basicStringLit, TTString Basic), 77 | (bareKey, TTBare) 78 | ] 79 | 80 | export 81 | lexTOML : String -> Maybe (List (WithBounds TOMLToken)) 82 | lexTOML str = 83 | case lex tomlTokenMap str of 84 | (tokens, (_, _, "")) => Just tokens 85 | _ => Nothing 86 | -------------------------------------------------------------------------------- /src/Language/TOML/Parser.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: MPL-2.0 4 | 5 | module Language.TOML.Parser 6 | 7 | import Language.TOML.ConcreteSyntax 8 | import Language.TOML.Tokens 9 | 10 | import Text.Parser 11 | import Text.Token 12 | 13 | import Data.Bool 14 | import Data.List 15 | import Data.List1 16 | 17 | -- this code does need to be repeated 18 | -- each clause has differentl laziness 19 | private 20 | fromEither : {c : _} -> Grammar state token c (Either String a) -> Grammar state token c a 21 | fromEither {c = False} act = do 22 | xb <- bounds act 23 | the (Grammar _ _ False a) $ 24 | case xb.val of 25 | Right x => pure x 26 | Left err => failLoc xb.bounds err 27 | fromEither {c = True} act = do 28 | xb <- bounds act 29 | the (Grammar _ _ False a) $ 30 | case xb.val of 31 | Right x => pure x 32 | Left err => failLoc xb.bounds err 33 | 34 | private 35 | punct : Punctuation -> Grammar state TOMLToken True () 36 | punct p = match $ TTPunct p 37 | 38 | private 39 | maybeNewlines : Grammar state TOMLToken False () 40 | maybeNewlines = do 41 | _ <- many (punct NewLine) 42 | pure () 43 | 44 | private 45 | newlines : Grammar state TOMLToken False () 46 | newlines = (some (punct NewLine) >>= \_ => pure ()) <|> eof 47 | 48 | private 49 | allowNewlines : (p : Grammar state TOMLToken True a) -> Grammar state TOMLToken True a 50 | allowNewlines p = maybeNewlines *> p <* maybeNewlines 51 | 52 | private 53 | string : Grammar state TOMLToken True CValue 54 | string = CVString <$> fromEither (terminal "string" getString) 55 | 56 | private 57 | boolean : Grammar state TOMLToken True CValue 58 | boolean = map CVBoolean $ match TTBoolean 59 | 60 | private 61 | integer : Grammar state TOMLToken True CValue 62 | integer = map CVInteger $ match TTInt 63 | 64 | private 65 | float : Grammar state TOMLToken True CValue 66 | float = map CVFloat $ match TTFloat 67 | 68 | private 69 | bare : Grammar state TOMLToken True String 70 | bare = match TTBare 71 | 72 | private 73 | key : Grammar state TOMLToken True CKey 74 | key = do 75 | first <- keyAtom 76 | rest <- many (punct Dot *> keyAtom) 77 | case rest of 78 | [] => pure $ CKAtom first 79 | rest => pure $ CKDotted (first:::rest) 80 | where 81 | keyAtom : Grammar state TOMLToken True CKeyAtom 82 | keyAtom = map CKBare bare 83 | <|> (map CKQuoted $ fromEither $ terminal "string key" getKeyString) 84 | 85 | mutual 86 | private 87 | value : Grammar state TOMLToken True CValue 88 | value = string 89 | <|> boolean 90 | <|> integer 91 | <|> float 92 | <|> array 93 | <|> inlineTable 94 | 95 | private 96 | array : Grammar state TOMLToken True CValue 97 | array = do 98 | punct (Square Open) 99 | commit 100 | vals <- sepBy (allowNewlines $ punct Comma) (allowNewlines value) 101 | punct (Square Close) 102 | pure $ CVArray vals 103 | 104 | private 105 | inlineTable : Grammar state TOMLToken True CValue 106 | inlineTable = do 107 | punct (Curly Open) 108 | commit 109 | vals <- sepBy (punct Comma) $ do 110 | k <- key 111 | punct Equal 112 | v <- value 113 | pure (k, v) 114 | 115 | punct (Curly Close) 116 | pure $ CVInlineTable vals 117 | 118 | private 119 | keyValue : Grammar state TOMLToken True Item 120 | keyValue = do 121 | k <- key 122 | punct Equal 123 | v <- value 124 | newlines 125 | pure $ IKeyValue k v 126 | 127 | private 128 | tableHeader : Grammar state TOMLToken True Item 129 | tableHeader = do 130 | punct (Square Open) 131 | k <- key 132 | commit 133 | punct (Square Close) 134 | newlines 135 | pure $ ITableHeader k 136 | 137 | private 138 | tableArrayHeader : Grammar state TOMLToken True Item 139 | tableArrayHeader = do 140 | punct (Square Open) 141 | punct (Square Open) 142 | commit 143 | k <- key 144 | punct (Square Close) 145 | punct (Square Close) 146 | newlines 147 | pure $ ITableArray k 148 | 149 | private 150 | item : Grammar state TOMLToken True Item 151 | item = keyValue 152 | <|> tableHeader 153 | <|> tableArrayHeader 154 | 155 | private 156 | items : Grammar state TOMLToken False (List Item) 157 | items = do 158 | maybeNewlines 159 | is <- many item 160 | maybeNewlines 161 | eof 162 | pure is 163 | 164 | export 165 | parseItems : List (WithBounds TOMLToken) -> Either (List String) (List Item) 166 | parseItems toks = case parse items $ filter (not . ignored) toks of 167 | Right (its, []) => Right its 168 | Right _ => Left ["unconsumed input"] 169 | Left errs => Left . flip map (forget errs) $ \(Error msg bounds) => 170 | case bounds of 171 | Just bounds => 172 | "\{show bounds.startLine}:\{show bounds.startCol}--\{show bounds.endLine}:\{show bounds.endCol}: \{msg}" 173 | Nothing => msg -------------------------------------------------------------------------------- /src/Language/TOML/Processing.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2022 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: MPL-2.0 4 | 5 | module Language.TOML.Processing 6 | 7 | import Data.List.Elem 8 | import Decidable.Equality 9 | import Language.TOML.Value 10 | 11 | export infixr 2 `And` 12 | 13 | mutual 14 | public export 15 | data ValueTy 16 | = TString 17 | | TInteger 18 | | TFloat 19 | | TBoolean 20 | | TEnum (List String) 21 | | TArray ValueTy 22 | | TTable TableTy 23 | 24 | public export 25 | record FieldTy where 26 | constructor MkFieldTy 27 | name : String 28 | optional : Bool 29 | ty : ValueTy 30 | 31 | public export 32 | data TableTy : Type where 33 | Emp : TableTy 34 | Ext : (ft : FieldTy) -> (FieldOf ft -> TableTy) -> TableTy 35 | 36 | public export 37 | And : FieldTy -> TableTy -> TableTy 38 | And x y = Ext x (const y) 39 | 40 | public export 41 | ValueOf : ValueTy -> Type 42 | ValueOf TString = String 43 | ValueOf TInteger = Integer 44 | ValueOf TFloat = Double 45 | ValueOf TBoolean = Bool 46 | ValueOf (TEnum names) = (name ** Elem name names) 47 | ValueOf (TArray t) = List (ValueOf t) 48 | ValueOf (TTable x) = TableOf x 49 | 50 | public export 51 | FieldOf : FieldTy -> Type 52 | FieldOf x = (if x.optional then Maybe else id) (ValueOf x.ty) 53 | 54 | public export 55 | data TableOf : TableTy -> Type where 56 | Nil : TableOf Emp 57 | (::) : (x : FieldOf ft) -> TableOf (f x) -> TableOf (Ext ft f) 58 | 59 | 60 | mutual 61 | public export 62 | data ValueError 63 | = ExpectedType ValueTy 64 | | InsideArray ValueError 65 | | InsideTable TableError 66 | | BadEnumVal String 67 | 68 | public export 69 | data TableError 70 | = FieldError String ValueError 71 | | ExpectedField String 72 | | UnexpectedFields (List String) 73 | 74 | 75 | mutual 76 | public export 77 | processTable : (ty : TableTy) -> Table -> Either TableError (TableOf ty) 78 | processTable Emp x with (keys x) 79 | _ | [] = Right [] 80 | _ | ks = Left $ UnexpectedFields ks 81 | processTable (Ext (MkFieldTy name optional ty) fields) x with (lookup name x) 82 | _ | Nothing = case optional of 83 | True => Right $ Nothing :: !(processTable (fields Nothing) x) 84 | False => Left $ ExpectedField name 85 | _ | Just val = do 86 | val' <- bimap (FieldError name) id $ processValue ty val 87 | let val'' = case optional of 88 | True => Just val' 89 | False => val' 90 | fields' <- processTable (fields val'') (delete name x) 91 | Right (val'' :: fields') 92 | 93 | public export 94 | processValue : (ty : ValueTy) -> Value -> Either ValueError (ValueOf ty) 95 | processValue (TEnum xs) (VString x) with (isElem x xs) 96 | _ | Yes el = Right (x ** el) 97 | _ | No nel = Left $ BadEnumVal x 98 | processValue TString (VString x) = Right x 99 | processValue TInteger (VInteger x) = Right x 100 | processValue TFloat (VFloat x) = Right x 101 | processValue TBoolean (VBoolean x) = Right x 102 | processValue (TArray t) (VArray xs) = traverse (bimap InsideArray id . processValue t) xs 103 | processValue (TTable t) (VTable x) = bimap InsideTable id $ processTable t x 104 | processValue t v = Left $ ExpectedType t 105 | -------------------------------------------------------------------------------- /src/Language/TOML/Tokens.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: MPL-2.0 4 | 5 | module Language.TOML.Tokens 6 | 7 | import Text.Bounded 8 | import Text.Token 9 | 10 | %default total 11 | 12 | public export 13 | strTrue : String 14 | strTrue = "true" 15 | 16 | public export 17 | strFalse : String 18 | strFalse = "false" 19 | 20 | public export 21 | data Bracket = Open | Close 22 | 23 | export 24 | Show Bracket where 25 | show Open = "open" 26 | show Close = "close" 27 | 28 | public export 29 | Eq Bracket where 30 | (==) Open Open = True 31 | (==) Close Close = True 32 | (==) _ _ = False 33 | 34 | public export 35 | data Punctuation 36 | = Comma 37 | | Dot 38 | | Equal 39 | | NewLine 40 | | Square Bracket 41 | | Curly Bracket 42 | 43 | export 44 | Show Punctuation where 45 | show Comma = "," 46 | show Dot = "." 47 | show Equal = "=" 48 | show NewLine = "\\n" 49 | show (Square Open) = "[" 50 | show (Square Close) = "]" 51 | show (Curly Open) = "(" 52 | show (Curly Close) = ")" 53 | 54 | public export 55 | Eq Punctuation where 56 | (==) Comma Comma = True 57 | (==) Dot Dot = True 58 | (==) Equal Equal = True 59 | (==) NewLine NewLine = True 60 | (==) (Square x) (Square y) = x == y 61 | (==) (Curly x) (Curly y) = x == y 62 | (==) _ _ = False 63 | 64 | ||| What sort of string this is 65 | ||| Names are taken from the [toml spec](https://toml.io/en/v1.0.0#string) 66 | public export 67 | data StringType : Type where 68 | ||| Double quoted, single-line string 69 | ||| Supports escaping 70 | ||| "hello \n world" 71 | Basic : StringType 72 | ||| Single quoted, singe-line string 73 | ||| Does not support escaping 74 | ||| 'hello \n world' 75 | Literal : StringType 76 | -- TODO: the following 77 | ||| Double quoted, multi-line string 78 | ||| Supports escaping and line folding 79 | BasicMultiline : StringType 80 | ||| Single quoted, multi-line string 81 | ||| Does not support escaping or line folding 82 | LiteralMultiline : StringType 83 | 84 | export 85 | Show StringType where 86 | show Basic = "Basic" 87 | show Literal = "Literal" 88 | show BasicMultiline = "BasicMultiline" 89 | show LiteralMultiline = "LiteralMultiline" 90 | 91 | export 92 | Eq StringType where 93 | Basic == Basic = True 94 | Literal == Literal = True 95 | BasicMultiline == BasicMultiline = True 96 | LiteralMultiline == LiteralMultiline = True 97 | _ == _ = False 98 | 99 | 100 | public export 101 | data TOMLTokenKind 102 | = TTBoolean 103 | | TTInt 104 | | TTFloat 105 | | TTString StringType 106 | | TTPunct Punctuation 107 | | TTBare 108 | | TTIgnored 109 | 110 | public export 111 | TOMLToken : Type 112 | TOMLToken = Token TOMLTokenKind 113 | 114 | export 115 | Show TOMLTokenKind where 116 | show TTBoolean = "boolean" 117 | show TTInt = "integer" 118 | show TTFloat = "float" 119 | show (TTString type) = "\{show type} string" 120 | show (TTPunct x) = show x 121 | show TTBare = "key" 122 | show TTIgnored = "comment" 123 | 124 | public export 125 | Eq TOMLTokenKind where 126 | (==) TTBoolean TTBoolean = True 127 | (==) TTInt TTInt = True 128 | (==) TTFloat TTFloat = True 129 | (==) (TTString x) (TTString y) = x == y 130 | (==) (TTPunct x) (TTPunct y) = x == y 131 | (==) TTBare TTBare = True 132 | (==) TTIgnored TTIgnored = True 133 | (==) _ _ = False 134 | 135 | charToInt : Char -> Integer 136 | charToInt c = 137 | if '0' <= c && c <= '9' 138 | then cast $ ord c - ord '0' 139 | else cast $ ord (toLower c) - ord 'a' 140 | 141 | parameters (sign, base : Integer) 142 | private 143 | parseIntLoop : 144 | List Char -> 145 | (acc : Integer) -> 146 | Integer 147 | parseIntLoop [] acc = acc 148 | parseIntLoop ('_'::rest) acc = parseIntLoop rest acc 149 | parseIntLoop (c::rest) acc = 150 | parseIntLoop rest (acc * base + charToInt c * sign) 151 | 152 | private 153 | parseWithSign : List Char -> (sign : Integer) -> Integer 154 | parseWithSign [] sign = 0 155 | parseWithSign ('0'::'b'::rest) sign = parseIntLoop sign 2 rest 0 156 | parseWithSign ('0'::'o'::rest) sign = parseIntLoop sign 8 rest 0 157 | parseWithSign ('0'::'x'::rest) sign = parseIntLoop sign 16 rest 0 158 | parseWithSign rest sign = parseIntLoop sign 10 rest 0 159 | 160 | private 161 | parseInt : List Char -> Integer 162 | parseInt [] = 0 163 | parseInt ('+'::rest) = parseWithSign rest 1 164 | parseInt ('-'::rest) = parseWithSign rest (-1) 165 | parseInt rest = parseWithSign rest 1 166 | 167 | nan : Double 168 | nan = sqrt (-1) 169 | 170 | inf : Double 171 | inf = 1.0 / 0.0 172 | 173 | namespace Float 174 | parameters (sign : Double) 175 | ||| parse the exponent part of a double 176 | ||| not including the e 177 | parseExponent : 178 | (number : Double) -> 179 | (acc : Integer) -> 180 | List Char -> 181 | Double 182 | parseExponent number acc [] = sign * number * pow 10 (cast acc) 183 | parseExponent number acc ('_'::rest) = parseExponent number acc rest 184 | parseExponent number acc (x::rest) = parseExponent number (10 * acc + charToInt x) rest 185 | 186 | ||| parse the decimal part of a double 187 | ||| not including the . 188 | ||| up to and including the e 189 | parseDecimal : 190 | (whole : Integer) -> 191 | (acc : Double) -> 192 | (exponent : Double) -> 193 | List Char -> 194 | Double 195 | parseDecimal whole acc exponent [] = sign * (cast whole + acc) 196 | parseDecimal whole acc exponent ('e'::rest) = parseExponent (cast whole + acc) 0 rest 197 | parseDecimal whole acc exponent ('E'::rest) = parseExponent (cast whole + acc) 0 rest 198 | parseDecimal whole acc exponent ('_'::rest) = parseDecimal whole acc exponent rest 199 | parseDecimal whole acc exponent (x::rest) = 200 | parseDecimal 201 | whole 202 | (acc + cast (charToInt x) * exponent) 203 | (exponent * 0.1) 204 | rest 205 | 206 | ||| parse the part of the double before the `.` 207 | parseWhole : (acc : Integer) -> List Char -> Double 208 | parseWhole acc [] = 0.0 209 | parseWhole acc ('.'::rest) = parseDecimal acc 0.0 0.1 rest 210 | parseWhole acc ('e'::rest) = parseExponent (cast acc) 0 rest 211 | parseWhole acc ('E'::rest) = parseExponent (cast acc) 0 rest 212 | parseWhole acc ('_'::rest) = parseWhole acc rest 213 | parseWhole acc (x::rest) = parseWhole (10 * acc + charToInt x) rest 214 | 215 | parseSign : List Char -> Double 216 | parseSign ('+'::rest) = parseWhole 1.0 0 rest 217 | parseSign ('-'::rest) = parseWhole (-1.0) 0 rest 218 | parseSign rest = parseWhole 1.0 0 rest 219 | 220 | export 221 | parseFloat : String -> Double 222 | parseFloat "nan" = nan 223 | parseFloat "+nan" = nan 224 | parseFloat "-nan" = -nan 225 | parseFloat "inf" = inf 226 | parseFloat "+inf" = inf 227 | parseFloat "-inf" = -inf 228 | parseFloat x = parseSign (unpack x) 229 | 230 | private 231 | unescapeBasic : List Char -> Either String (List Char) 232 | unescapeBasic ('"'::rest) = loop rest 233 | where 234 | -- hex digit to int 235 | hexToInt : Char -> Either String Int 236 | hexToInt c = 237 | if isHexDigit c 238 | then Right $ 239 | if '0' <= c && c <= '9' 240 | then ord c - ord '0' 241 | else ord (toLower c) - ord 'a' 242 | else Left "invalid hex character: '\{cast {to=String} c}'" 243 | 244 | unicodeEscape : List Char -> (acc : Int) -> Either String Char 245 | unicodeEscape [] acc = pure $ chr acc 246 | unicodeEscape (c::cs) acc = do 247 | x <- hexToInt c 248 | unicodeEscape cs (acc * 16 + x) 249 | 250 | loop : List Char -> Either String (List Char) 251 | loop [] = Left "unexpected end of input" 252 | loop ('"'::_) = Right [] 253 | loop ('\\'::'b'::rest) = ('\b' ::) <$> loop rest 254 | loop ('\\'::'t'::rest) = ('\t' ::) <$> loop rest 255 | loop ('\\'::'n'::rest) = ('\n' ::) <$> loop rest 256 | loop ('\\'::'f'::rest) = ('\f' ::) <$> loop rest 257 | loop ('\\'::'r'::rest) = ('\r' ::) <$> loop rest 258 | loop ('\\'::'"'::rest) = ('"' ::) <$> loop rest 259 | loop ('\\'::'\\'::rest) = ('\\' ::) <$> loop rest 260 | loop ('\\'::'u'::u0::u1::u2::u3::rest) = do 261 | c <- unicodeEscape [u0, u1, u2, u3] 0 262 | (c ::) <$> loop rest 263 | loop ('\\'::'U'::u0::u1::u2::u3::u4::u5::u6::u7::rest) = do 264 | c <- unicodeEscape [u0, u1, u2, u3, u4, u5, u6, u7] 0 265 | (c ::) <$> loop rest 266 | loop ('\\'::_) = Left "invalid escape code" 267 | loop (x::rest) = (x ::) <$> loop rest 268 | unescapeBasic _ = Left "expected quote" 269 | 270 | public export 271 | TokenKind TOMLTokenKind where 272 | TokType TTBoolean = Bool 273 | TokType TTInt = Integer 274 | TokType TTFloat = Double 275 | -- a string accepted by the lexer isn't necessarily 276 | -- a valid toml string 277 | TokType (TTString _) = Either String String 278 | TokType (TTPunct _) = () 279 | TokType TTBare = String 280 | TokType TTIgnored = () 281 | 282 | tokValue TTBoolean s = s == strTrue 283 | tokValue TTInt s = parseInt (unpack s) 284 | tokValue TTFloat s = parseFloat s 285 | 286 | tokValue (TTString Basic) s = map pack $ unescapeBasic (unpack s) 287 | tokValue (TTString Literal) s = Left "unimplemted string type: literal" 288 | tokValue (TTString BasicMultiline) s = Left "unimplemted string type: basic multiline" 289 | tokValue (TTString LiteralMultiline) s = Left "unimplemted string type: literal multiline" 290 | 291 | tokValue (TTPunct _) _ = () 292 | tokValue TTBare s = s 293 | tokValue TTIgnored _ = () 294 | 295 | export 296 | getString : Token TOMLTokenKind -> Maybe (Either String String) 297 | getString tok@(Tok ((TTString _)) text) = Just (value tok) 298 | getString _ = Nothing 299 | 300 | export 301 | getKeyString : Token TOMLTokenKind -> Maybe (Either String String) 302 | getKeyString tok@(Tok ((TTString Basic)) text) = Just (value tok) 303 | getKeyString tok@(Tok ((TTString Literal)) text) = Just (value tok) 304 | getKeyString _ = Nothing 305 | 306 | export 307 | ignored : WithBounds TOMLToken -> Bool 308 | ignored (MkBounded (Tok TTIgnored _) _ _) = True 309 | ignored _ = False -------------------------------------------------------------------------------- /src/Language/TOML/Value.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: MPL-2.0 4 | 5 | module Language.TOML.Value 6 | 7 | import public Data.SortedMap 8 | import Data.List 9 | import Data.String 10 | 11 | public export 12 | Key : Type 13 | Key = String 14 | 15 | mutual 16 | public export 17 | data Value 18 | = VString String 19 | | VInteger Integer 20 | | VFloat Double 21 | | VBoolean Bool 22 | | VArray (List Value) 23 | | VTable Table 24 | 25 | public export 26 | Table : Type 27 | Table = SortedMap Key Value 28 | 29 | 30 | export 31 | lookupNested : (key : List String) -> (table : Table) -> Maybe Value 32 | lookupNested [] table = Nothing 33 | lookupNested [x] table = lookup x table 34 | lookupNested (x :: xs) table = do 35 | VTable t <- lookup x table 36 | | _ => Nothing 37 | lookupNested xs t 38 | 39 | 40 | public export 41 | Eq Value where 42 | (VString x) == (VString y) = x == y 43 | (VInteger x) == (VInteger y) = x == y 44 | (VFloat x) == (VFloat y) = x == y 45 | (VBoolean x) == (VBoolean y) = x == y 46 | (VArray xs) == (VArray ys) = assert_total $ xs == ys 47 | (VTable x) == (VTable y) = assert_total $ SortedMap.toList x == SortedMap.toList y 48 | _ == _ = False 49 | 50 | a /= b = not $ (assert_total (==)) a b 51 | 52 | 53 | public export 54 | Show Value where 55 | show (VString x) = show x 56 | show (VInteger x) = show x 57 | show (VFloat x) = show x 58 | show (VBoolean True) = "true" 59 | show (VBoolean False) = "false" 60 | show (VArray xs) = "[" 61 | ++ fastConcat (intersperse ", " $ map (assert_total show) xs) 62 | ++ "]" 63 | show (VTable x) = 64 | let kvs = the (List (Key, Value)) $ toList x in 65 | "{" 66 | ++ fastConcat (intersperse ", " . flip map kvs $ \(k, v) => 67 | show k ++ " = " ++ assert_total show v 68 | ) 69 | ++ "}" 70 | 71 | export 72 | [Raw] Show Value where 73 | show (VString x) = "string \{show x}" 74 | show (VInteger x) = "integer \{show x}" 75 | show (VFloat x) = "float \{show x}" 76 | show (VBoolean x) = if x then "bool true" else "bool false" 77 | show (VArray xs) = "list [\{concat $ intersperse ", " $ map (assert_total show) xs}]" 78 | show (VTable x) = 79 | let kvs = SortedMap.toList x in 80 | "{\{fastConcat (intersperse ", " . flip map kvs $ \(k, v) => 81 | show k ++ " = " ++ assert_total show v 82 | )}}" 83 | 84 | -------------------------------------------------------------------------------- /tests.ipkg: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: CC0-1.0 4 | 5 | package toml_tests 6 | version = 0.1.0 7 | 8 | depends = toml, contrib, tester 9 | 10 | modules = 11 | Files, 12 | Lexer, 13 | Parser, 14 | Tests 15 | 16 | executable = "tests" 17 | 18 | sourcedir = "tests" 19 | 20 | main = Tests 21 | -------------------------------------------------------------------------------- /tests/Files.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: CC0-1.0 4 | 5 | module Files 6 | 7 | import Tester 8 | 9 | import Language.TOML 10 | 11 | 12 | import Data.List 13 | import System.Directory 14 | import System.File 15 | 16 | 17 | parse : String -> TestFunc Table 18 | parse src = do 19 | Right table <- pure $ parseTOML src 20 | | Left err => throw (show err) 21 | pure table 22 | 23 | dirEntries : (path : String) -> TestFunc (List String) 24 | dirEntries path = do 25 | 26 | Right contents <- listDir path 27 | | Left err => 28 | throw $ "\nUnable to open dir \"" ++ path ++ "\": " ++ show err 29 | 30 | pure $ filter (\x => not $ x `elem` [".", ".."]) contents 31 | 32 | 33 | 34 | filesPass : Test 35 | filesPass = test "valid files" $ do 36 | let basePath = "tests/pass/" 37 | dirs <- dirEntries basePath 38 | for_ dirs $ \path => do 39 | Right src <- readFile (basePath ++ path) 40 | | Left err => throw $ show err 41 | 42 | Right _ <- pure $ parseTOML src 43 | | Left err => throw $ show err 44 | 45 | pure () 46 | 47 | 48 | export 49 | tests : List Test 50 | tests = [ 51 | filesPass 52 | ] -------------------------------------------------------------------------------- /tests/Lexer.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: CC0-1.0 4 | 5 | module Lexer 6 | 7 | import Text.Lexer 8 | 9 | import Tester 10 | 11 | import Language.TOML.Lexer 12 | import Language.TOML.Tokens 13 | 14 | tokenize : Test 15 | tokenize = test "tokenize" $ do 16 | let Just res = lexTOML "hello world\n" 17 | | Nothing => throwE "lexer error" 18 | assertEq (length res) 4 19 | 20 | integerLiteral : Test 21 | integerLiteral = test "lex integer literals" $ do 22 | let Just res = lexTOML "12345 12_345 0x12345 0x12_345" 23 | | Nothing => throwE "lexer error" 24 | assertEq (length res) 7 25 | 26 | floatLiteral : Test 27 | floatLiteral = test "lex float literals" $ do 28 | let Just res = lexTOML "5.0 0.55 0.0 -7.8e7 nan +nan -inf +inf" 29 | | Nothing => throwE "lexer error" 30 | assertEq (length res) 15 31 | 32 | stringLiteral : Test 33 | stringLiteral = test "lex string literals" $ do 34 | let Just res = lexTOML #""hello world""# 35 | | Nothing => throwE "lexer error" 36 | assertEq (length res) 1 37 | 38 | export 39 | tests : List Test 40 | tests = [tokenize, integerLiteral, floatLiteral, stringLiteral] 41 | -------------------------------------------------------------------------------- /tests/Parser.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: CC0-1.0 4 | 5 | module Parser 6 | 7 | import Tester 8 | import Language.Reflection 9 | import Control.ANSI 10 | 11 | import Text.Lexer 12 | 13 | import Language.TOML 14 | import Language.TOML.Tokens 15 | import Language.TOML.Parser as P 16 | import Language.TOML.Lexer as L 17 | import Language.TOML.ConcreteSyntax 18 | import Language.TOML.Value 19 | 20 | %language ElabReflection 21 | 22 | parseToItems : String -> TestFunc (List Item) 23 | parseToItems src = do 24 | Just toks <- pure $ L.lexTOML src 25 | | Nothing => throw "lexing failed" 26 | Right items <- pure $ P.parseItems toks 27 | | Left err => throw (show (colored Red "parsing failed: ") ++ show err) 28 | pure items 29 | 30 | 31 | parse : String -> TestFunc Table 32 | parse src = do 33 | Right table <- pure $ parseTOML src 34 | | Left err => throw (show err) 35 | pure table 36 | 37 | namespace Concrete 38 | export 39 | kvNoNewline : Test 40 | kvNoNewline = test "parse key-value no newline" $ do 41 | items <- parseToItems "x = 12" 42 | assertEq (show items) "[keyval: x = 12]" 43 | 44 | export 45 | kvComment : Test 46 | kvComment = test "parse key-value with comment" $ do 47 | items <- parseToItems "x = 12 # this is a key value pair" 48 | assertEq (show items) "[keyval: x = 12]" 49 | 50 | export 51 | kvNewline : Test 52 | kvNewline = test "parse key-value with newline" $ do 53 | items <- parseToItems "x = 12\n" 54 | assertEq (show items) "[keyval: x = 12]" 55 | 56 | export 57 | tableHeader : Test 58 | tableHeader = test "parse table header" $ do 59 | items <- parseToItems "[package]" 60 | assertEq (show items) "[table: package]" 61 | 62 | export 63 | tableHeaderDotted : Test 64 | tableHeaderDotted = test "parse table header with dotted key" $ do 65 | items <- parseToItems "[dependencies.test]" 66 | assertEq (show items) "[table: dependencies.test]" 67 | 68 | export 69 | tableArray : Test 70 | tableArray = test "parse table array header" $ do 71 | items <- parseToItems "[[bin]]" 72 | assertEq (show items) "[tablearr: bin]" 73 | 74 | export 75 | tableArrayDotted : Test 76 | tableArrayDotted = test "parse table array header with dotted key" $ do 77 | items <- parseToItems "[[bin.tags]]" 78 | assertEq (show items) "[tablearr: bin.tags]" 79 | 80 | 81 | export 82 | emptyFile : Test 83 | emptyFile = test "parse empty file" $ do 84 | items <- parseToItems "" 85 | assertEq (show items) "[]" 86 | 87 | export 88 | kvArrayNewLine : Test 89 | kvArrayNewLine = test "key-val with array with newlines" $ do 90 | items <- parseToItems "x = [\n\t1,\n\t2,\n\t3\n]" 91 | assertEq (show items) "[keyval: x = [1, 2, 3]]" 92 | 93 | export 94 | kvInlineTable : Test 95 | kvInlineTable = test "key-val with inline table" $ do 96 | items <- parseToItems "test = { path = \"../test-idr\" }" 97 | -- TODO strings are not interspreted *and* are `show`n 98 | assertEq (show items) "[keyval: test = {path = \"../test-idr\"}]" 99 | 100 | 101 | 102 | 103 | namespace Abstract 104 | export 105 | kvGlobal : Test 106 | kvGlobal = test "global key-val" $ do 107 | table <- parse "x = 12" 108 | assertEq [("x", VInteger 12)] (toList table) 109 | 110 | export 111 | kvNested : Test 112 | kvNested = test "global nested key-val" $ do 113 | table <- parse "x.y = 12" 114 | assertEq (lookupNested ["x", "y"] table) (Just $ VInteger 12) 115 | 116 | export 117 | tableSectionKv : Test 118 | tableSectionKv = test "parse table section key-val" $ do 119 | table <- parse "[table-name]\nx = 12" 120 | assertEq (lookupNested ["table-name", "x"] table) (Just $ VInteger 12) 121 | 122 | export 123 | tableSectionNestedKv : Test 124 | tableSectionNestedKv = test "parse table section nested key-val" $ do 125 | table <- parse "[table-name]\nx.y = 12" 126 | assertEq (lookupNested ["table-name", "x", "y"] table) (Just $ VInteger 12) 127 | 128 | export 129 | inlineTable : Test 130 | inlineTable = test "parse inline table" $ do 131 | table <- parse "test = { x = 12, y = 21 }" 132 | assertEq (lookupNested ["test", "x"] table) (Just $ VInteger 12) 133 | 134 | export 135 | array : Test 136 | array = test "parse array" $ do 137 | table <- parse "x = [1, 3, 7]" 138 | assertEq {loc = here `(())} (lookup "x" table) (Just $ VArray [VInteger 1, VInteger 3, VInteger 7]) 139 | 140 | export 141 | integers : Test 142 | integers = test "parsing integers" $ do 143 | integers <- parse "x = [2, 42, -78, +47, 0x123, 0x1005, 0o55, 0o006, 0b11011]" 144 | assertEq {loc = here `(())} 145 | (lookup "x" integers) 146 | (Just $ VArray (map VInteger [2, 42, -78, 47, 0x123, 0x1005, 0o55, 0o6, 0b11011])) 147 | 148 | export 149 | floats : Test 150 | floats = test "parsing floats" $ do 151 | floats <- parse "x = [0.0, 0.1, 1.0, 42.84, 5e4, 2.12e3]" 152 | assertEq {loc = here `(())} 153 | (lookup "x" floats) 154 | (Just $ VArray $ map VFloat [0.0, 0.1, 1.0, 42.84, 50000, 2120]) 155 | 156 | nan : Double 157 | nan = sqrt (-1) 158 | 159 | inf : Double 160 | inf = 1.0 / 0.0 161 | 162 | export 163 | specialFloats : Test 164 | specialFloats = test "parsing special floats" $ do 165 | nans <- parse "x = [nan, +nan, -nan]" 166 | infs <- parse "x = [inf, +inf, -inf]" 167 | assertEq {loc = here `(())} 168 | (lookup "x" infs) 169 | (Just $ VArray $ map VFloat [inf, inf, -inf]) 170 | case lookup "x" nans of 171 | Just (VArray nans) => assert $ all isNan nans 172 | _ => throw "not an array" 173 | where 174 | isNan : Value -> Bool 175 | isNan (VFloat x) = x /= x 176 | isNan _ = False 177 | 178 | export 179 | strings : Test 180 | strings = test "parsing strings" $ do 181 | hello_world <- parse #"x = "hello world""# 182 | assertEq {loc = here `(())} (lookup "x" hello_world) (Just $ VString "hello world") 183 | 184 | export 185 | tableArray : Test 186 | tableArray = test "parsing table arrays" $ do 187 | array <- parse """ 188 | [[depends]] 189 | name = "toml" 190 | version = "1.2" 191 | 192 | [[depends]] 193 | name = "hashable" 194 | version = "9.7" 195 | """ 196 | 197 | case lookup "depends" array of 198 | Just (VArray [VTable toml, VTable hashable]) => do 199 | let loc = here `(()) 200 | assertEq {loc} (lookup "name" toml) (Just $ VString "toml") 201 | assertEq {loc} (lookup "name" hashable) (Just $ VString "hashable") 202 | assertEq {loc} (lookup "version" toml) (Just $ VString "1.2") 203 | assertEq {loc} (lookup "version" hashable) (Just $ VString "9.7") 204 | Just (VArray xs) => throw "expected array of 2 tables, got: \{show xs}" 205 | Just val => throw "expected array, got: \{show val}" 206 | Nothing => throw "missing 'depends'" 207 | 208 | public export 209 | tests : List Test 210 | tests = [ 211 | Concrete.kvNoNewline, 212 | Concrete.kvComment, 213 | Concrete.kvNewline, 214 | Concrete.tableHeader, 215 | Concrete.tableHeaderDotted, 216 | Concrete.tableArray, 217 | Concrete.tableArrayDotted, 218 | Concrete.emptyFile, 219 | Concrete.kvArrayNewLine, 220 | Concrete.kvInlineTable, 221 | 222 | Abstract.kvGlobal, 223 | Abstract.kvNested, 224 | Abstract.tableSectionKv, 225 | Abstract.tableSectionNestedKv, 226 | Abstract.inlineTable, 227 | Abstract.array, 228 | Abstract.integers, 229 | Abstract.floats, 230 | Abstract.specialFloats, 231 | Abstract.strings, 232 | Abstract.tableArray 233 | ] 234 | -------------------------------------------------------------------------------- /tests/Process.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2022 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: CC0-1.0 4 | 5 | module Process 6 | 7 | import Tester 8 | 9 | import Data.List.Quantifiers 10 | import Language.TOML 11 | import Language.TOML.Processing 12 | import Data.List.Elem 13 | 14 | basicUnordered : Test 15 | basicUnordered = test "process unordered table" $ assert $ check result 16 | where 17 | Spec : TableTy 18 | Spec = MkFieldTy "name" False TString `And` MkFieldTy "age" False TInteger `And` Emp 19 | 20 | table : Table 21 | table = fromList [("age", VInteger 999), ("name", VString "John Doe")] 22 | 23 | result : Either TableError (TableOf Spec) 24 | result = processTable Spec table 25 | 26 | check : Either TableError (TableOf Spec) -> Bool 27 | check (Left x) = False 28 | check (Right [name, age]) = name == "John Doe" && age == 999 29 | 30 | basicNested : Test 31 | basicNested = test "process nested table" $ assert $ check result 32 | where 33 | Spec : TableTy 34 | Spec = MkFieldTy "name" False TString `And` 35 | MkFieldTy "age" False TInteger `And` 36 | MkFieldTy "skills" False (TTable 37 | (MkFieldTy "running" False TInteger `And` 38 | MkFieldTy "programming" False TInteger `And` 39 | Emp)) `And` 40 | Emp 41 | 42 | table : Table 43 | table = fromList [("age", VInteger 999), 44 | ("name", VString "John Doe"), 45 | ("skills", VTable $ fromList 46 | [("running", VInteger 5), 47 | ("programming", VInteger 8)])] 48 | 49 | result : Either TableError (TableOf Spec) 50 | result = processTable Spec table 51 | 52 | check : Either TableError (TableOf Spec) -> Bool 53 | check (Left x) = False 54 | check (Right [name, age, [running, programming]]) = 55 | name == "John Doe" && age == 999 && running == 5 && programming == 8 56 | 57 | basicOptional : Test 58 | basicOptional = test "process table with optional field" $ assert $ check result 59 | where 60 | Spec : TableTy 61 | Spec = MkFieldTy "name" True TString `And` MkFieldTy "age" False TInteger `And` Emp 62 | 63 | table : Table 64 | table = fromList [("age", VInteger 999)] 65 | 66 | result : Either TableError (TableOf Spec) 67 | result = processTable Spec table 68 | 69 | check : Either TableError (TableOf Spec) -> Bool 70 | check (Left x) = False 71 | check (Right [name, age]) = name == Nothing && age == 999 72 | 73 | basicDependent : Test 74 | basicDependent = test "process table dependent layout" $ assert $ check result 75 | where 76 | Spec : TableTy 77 | Spec = Ext (MkFieldTy "programmer" False TBoolean) $ \programmer => 78 | if programmer 79 | then MkFieldTy "fave-lang" False TString `And` Emp 80 | else Emp 81 | 82 | table : Table 83 | table = fromList [("programmer", VBoolean True), ("fave-lang", VString "idris")] 84 | 85 | result : Either TableError (TableOf Spec) 86 | result = processTable Spec table 87 | 88 | check : Either TableError (TableOf Spec) -> Bool 89 | check (Left x) = False 90 | check (Right (True :: lang :: [])) = lang == "idris" 91 | check (Right (False :: tbl)) = False 92 | 93 | basicEnum : Test 94 | basicEnum = test "process enum" $ assert $ check result 95 | where 96 | Spec : ValueTy 97 | Spec = TEnum ["idris", "haskell", "lisp"] 98 | 99 | table : Value 100 | table = VString "idris" 101 | 102 | result : Either ValueError (ValueOf Spec) 103 | result = processValue Spec table 104 | 105 | check : Either ValueError (ValueOf Spec) -> Bool 106 | check (Left x) = False 107 | check (Right ("idris" ** _)) = True 108 | check (Right (_ ** _)) = False 109 | 110 | 111 | export 112 | tests : List Test 113 | tests = [basicUnordered, basicNested, basicOptional, basicDependent, basicEnum] 114 | -------------------------------------------------------------------------------- /tests/Tests.idr: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: CC0-1.0 4 | 5 | module Tests 6 | 7 | import Tester 8 | import Tester.Runner 9 | 10 | import Parser 11 | import Lexer 12 | import Files 13 | import Process 14 | 15 | tests : List Test 16 | tests = Lexer.tests 17 | ++ Parser.tests 18 | ++ Files.tests 19 | ++ Process.tests 20 | 21 | main : IO () 22 | main = do 23 | success <- runTests Tests.tests 24 | if success 25 | then putStrLn "All tests passed." 26 | else putStrLn "Not all tests passed." 27 | -------------------------------------------------------------------------------- /tests/pass/test.toml: -------------------------------------------------------------------------------- 1 | # Description of the package 2 | [package] 3 | name = "test-app" 4 | license = "MPL" 5 | 6 | packages = ["contrib"] 7 | 8 | [bin] 9 | name = "test-app" 10 | module = "TestApp.Main" 11 | 12 | 13 | # Write the dependencies here 14 | 15 | [dependencies] 16 | test = { git = "https://github.com/tiatomee/test-idr", tag = "0.1.0" } 17 | 18 | [dependencies.toml] 19 | git = "https://github.com/tiatomee/toml-idr" 20 | branch = "main" # switch to a semver tag -------------------------------------------------------------------------------- /toml.ipkg: -------------------------------------------------------------------------------- 1 | -- SPDX-FileCopyrightText: 2021 The toml-idr developers 2 | -- 3 | -- SPDX-License-Identifier: CC0-1.0 4 | 5 | package toml 6 | version = 0.1.0 7 | 8 | depends = contrib 9 | 10 | modules = 11 | Language.TOML.ConcreteSyntax, 12 | Language.TOML.Parser, 13 | Language.TOML.Lexer, 14 | Language.TOML.Tokens, 15 | Language.TOML.Value, 16 | Language.TOML.Processing, 17 | Language.TOML 18 | 19 | sourcedir = "src" 20 | --------------------------------------------------------------------------------