├── LICENSE ├── README.md ├── doc-pkg ├── .gitignore ├── Cargo.toml └── src.rs ├── enum-as-str-test ├── .gitignore ├── Cargo.toml └── src │ └── main.rs ├── enum-as-str ├── .gitignore ├── Cargo.toml └── src │ └── lib.rs ├── parse-generics-poc ├── .gitignore ├── Cargo.toml ├── src │ └── lib.rs └── tests │ ├── derive_clone_copy.rs │ ├── derive_iterator.rs │ ├── simple.rs │ └── wrap_fn.rs ├── parse-generics-shim ├── .gitignore ├── Cargo.toml ├── src │ ├── lib.rs │ ├── parse_constr.rs │ ├── parse_generics_shim.rs │ └── parse_where_shim.rs └── tests │ ├── parse_constr.rs │ ├── parse_generics.rs │ └── parse_where.rs ├── parse-macros ├── .gitignore ├── Cargo.toml ├── build.rs ├── src │ ├── lib.rs │ ├── parse_enum.rs │ ├── parse_item.rs │ ├── parse_macros_util.rs │ ├── parse_struct.rs │ └── parse_type_item.rs └── tests │ ├── derive_clone.rs │ ├── derive_partial_ord.rs │ ├── derive_serialize.rs │ ├── reflect.rs │ └── simple.rs └── scripts └── update-docs.py /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright ⓒ 2016 Daniel Keep. 2 | 3 | Licensed under either of: 4 | 5 | * MIT license, or 6 | * Apache License, Version 2.0 7 | 8 | at your option. 9 | 10 | Unless you explicitly state otherwise, any contribution intentionally 11 | submitted for inclusion in the work by you shall be dual licensed as 12 | above, without any additional terms or conditions. 13 | 14 | # MIT License 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining 17 | a copy of this software and associated documentation files (the 18 | "Software"), to deal in the Software without restriction, including 19 | without limitation the rights to use, copy, modify, merge, publish, 20 | distribute, sublicense, and/or sell copies of the Software, and to 21 | permit persons to whom the Software is furnished to do so, subject 22 | to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included 25 | in all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 28 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 31 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 32 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33 | OTHER DEALINGS IN THE SOFTWARE. 34 | 35 | # Apache License, Version 2.0 36 | 37 | Apache License 38 | Version 2.0, January 2004 39 | http://www.apache.org/licenses/ 40 | 41 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 42 | 43 | 1. Definitions. 44 | 45 | "License" shall mean the terms and conditions for use, reproduction, 46 | and distribution as defined by Sections 1 through 9 of this document. 47 | 48 | "Licensor" shall mean the copyright owner or entity authorized by 49 | the copyright owner that is granting the License. 50 | 51 | "Legal Entity" shall mean the union of the acting entity and all 52 | other entities that control, are controlled by, or are under common 53 | control with that entity. For the purposes of this definition, 54 | "control" means (i) the power, direct or indirect, to cause the 55 | direction or management of such entity, whether by contract or 56 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 57 | outstanding shares, or (iii) beneficial ownership of such entity. 58 | 59 | "You" (or "Your") shall mean an individual or Legal Entity 60 | exercising permissions granted by this License. 61 | 62 | "Source" form shall mean the preferred form for making modifications, 63 | including but not limited to software source code, documentation 64 | source, and configuration files. 65 | 66 | "Object" form shall mean any form resulting from mechanical 67 | transformation or translation of a Source form, including but 68 | not limited to compiled object code, generated documentation, 69 | and conversions to other media types. 70 | 71 | "Work" shall mean the work of authorship, whether in Source or 72 | Object form, made available under the License, as indicated by a 73 | copyright notice that is included in or attached to the work 74 | (an example is provided in the Appendix below). 75 | 76 | "Derivative Works" shall mean any work, whether in Source or Object 77 | form, that is based on (or derived from) the Work and for which the 78 | editorial revisions, annotations, elaborations, or other modifications 79 | represent, as a whole, an original work of authorship. For the purposes 80 | of this License, Derivative Works shall not include works that remain 81 | separable from, or merely link (or bind by name) to the interfaces of, 82 | the Work and Derivative Works thereof. 83 | 84 | "Contribution" shall mean any work of authorship, including 85 | the original version of the Work and any modifications or additions 86 | to that Work or Derivative Works thereof, that is intentionally 87 | submitted to Licensor for inclusion in the Work by the copyright owner 88 | or by an individual or Legal Entity authorized to submit on behalf of 89 | the copyright owner. For the purposes of this definition, "submitted" 90 | means any form of electronic, verbal, or written communication sent 91 | to the Licensor or its representatives, including but not limited to 92 | communication on electronic mailing lists, source code control systems, 93 | and issue tracking systems that are managed by, or on behalf of, the 94 | Licensor for the purpose of discussing and improving the Work, but 95 | excluding communication that is conspicuously marked or otherwise 96 | designated in writing by the copyright owner as "Not a Contribution." 97 | 98 | "Contributor" shall mean Licensor and any individual or Legal Entity 99 | on behalf of whom a Contribution has been received by Licensor and 100 | subsequently incorporated within the Work. 101 | 102 | 2. Grant of Copyright License. Subject to the terms and conditions of 103 | this License, each Contributor hereby grants to You a perpetual, 104 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 105 | copyright license to reproduce, prepare Derivative Works of, 106 | publicly display, publicly perform, sublicense, and distribute the 107 | Work and such Derivative Works in Source or Object form. 108 | 109 | 3. Grant of Patent License. Subject to the terms and conditions of 110 | this License, each Contributor hereby grants to You a perpetual, 111 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 112 | (except as stated in this section) patent license to make, have made, 113 | use, offer to sell, sell, import, and otherwise transfer the Work, 114 | where such license applies only to those patent claims licensable 115 | by such Contributor that are necessarily infringed by their 116 | Contribution(s) alone or by combination of their Contribution(s) 117 | with the Work to which such Contribution(s) was submitted. If You 118 | institute patent litigation against any entity (including a 119 | cross-claim or counterclaim in a lawsuit) alleging that the Work 120 | or a Contribution incorporated within the Work constitutes direct 121 | or contributory patent infringement, then any patent licenses 122 | granted to You under this License for that Work shall terminate 123 | as of the date such litigation is filed. 124 | 125 | 4. Redistribution. You may reproduce and distribute copies of the 126 | Work or Derivative Works thereof in any medium, with or without 127 | modifications, and in Source or Object form, provided that You 128 | meet the following conditions: 129 | 130 | (a) You must give any other recipients of the Work or 131 | Derivative Works a copy of this License; and 132 | 133 | (b) You must cause any modified files to carry prominent notices 134 | stating that You changed the files; and 135 | 136 | (c) You must retain, in the Source form of any Derivative Works 137 | that You distribute, all copyright, patent, trademark, and 138 | attribution notices from the Source form of the Work, 139 | excluding those notices that do not pertain to any part of 140 | the Derivative Works; and 141 | 142 | (d) If the Work includes a "NOTICE" text file as part of its 143 | distribution, then any Derivative Works that You distribute must 144 | include a readable copy of the attribution notices contained 145 | within such NOTICE file, excluding those notices that do not 146 | pertain to any part of the Derivative Works, in at least one 147 | of the following places: within a NOTICE text file distributed 148 | as part of the Derivative Works; within the Source form or 149 | documentation, if provided along with the Derivative Works; or, 150 | within a display generated by the Derivative Works, if and 151 | wherever such third-party notices normally appear. The contents 152 | of the NOTICE file are for informational purposes only and 153 | do not modify the License. You may add Your own attribution 154 | notices within Derivative Works that You distribute, alongside 155 | or as an addendum to the NOTICE text from the Work, provided 156 | that such additional attribution notices cannot be construed 157 | as modifying the License. 158 | 159 | You may add Your own copyright statement to Your modifications and 160 | may provide additional or different license terms and conditions 161 | for use, reproduction, or distribution of Your modifications, or 162 | for any such Derivative Works as a whole, provided Your use, 163 | reproduction, and distribution of the Work otherwise complies with 164 | the conditions stated in this License. 165 | 166 | 5. Submission of Contributions. Unless You explicitly state otherwise, 167 | any Contribution intentionally submitted for inclusion in the Work 168 | by You to the Licensor shall be under the terms and conditions of 169 | this License, without any additional terms or conditions. 170 | Notwithstanding the above, nothing herein shall supersede or modify 171 | the terms of any separate license agreement you may have executed 172 | with Licensor regarding such Contributions. 173 | 174 | 6. Trademarks. This License does not grant permission to use the trade 175 | names, trademarks, service marks, or product names of the Licensor, 176 | except as required for reasonable and customary use in describing the 177 | origin of the Work and reproducing the content of the NOTICE file. 178 | 179 | 7. Disclaimer of Warranty. Unless required by applicable law or 180 | agreed to in writing, Licensor provides the Work (and each 181 | Contributor provides its Contributions) on an "AS IS" BASIS, 182 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 183 | implied, including, without limitation, any warranties or conditions 184 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 185 | PARTICULAR PURPOSE. You are solely responsible for determining the 186 | appropriateness of using or redistributing the Work and assume any 187 | risks associated with Your exercise of permissions under this License. 188 | 189 | 8. Limitation of Liability. In no event and under no legal theory, 190 | whether in tort (including negligence), contract, or otherwise, 191 | unless required by applicable law (such as deliberate and grossly 192 | negligent acts) or agreed to in writing, shall any Contributor be 193 | liable to You for damages, including any direct, indirect, special, 194 | incidental, or consequential damages of any character arising as a 195 | result of this License or out of the use or inability to use the 196 | Work (including but not limited to damages for loss of goodwill, 197 | work stoppage, computer failure or malfunction, or any and all 198 | other commercial damages or losses), even if such Contributor 199 | has been advised of the possibility of such damages. 200 | 201 | 9. Accepting Warranty or Additional Liability. While redistributing 202 | the Work or Derivative Works thereof, You may choose to offer, 203 | and charge a fee for, acceptance of support, warranty, indemnity, 204 | or other liability obligations and/or rights consistent with this 205 | License. However, in accepting such obligations, You may act only 206 | on Your own behalf and on Your sole responsibility, not on behalf 207 | of any other Contributor, and only if You agree to indemnify, 208 | defend, and hold each Contributor harmless for any liability 209 | incurred by, or claims asserted against, such Contributor by reason 210 | of your accepting any such warranty or additional liability. 211 | 212 | END OF TERMS AND CONDITIONS 213 | 214 | APPENDIX: How to apply the Apache License to your work. 215 | 216 | To apply the Apache License to your work, attach the following 217 | boilerplate notice, with the fields enclosed by brackets "[]" 218 | replaced with your own identifying information. (Don't include 219 | the brackets!) The text should be enclosed in the appropriate 220 | comment syntax for the file format. We also recommend that a 221 | file or class name and description of purpose be included on the 222 | same "printed page" as the copyright notice for easier 223 | identification within third-party archives. 224 | 225 | Copyright [yyyy] [name of copyright owner] 226 | 227 | Licensed under the Apache License, Version 2.0 (the "License"); 228 | you may not use this file except in compliance with the License. 229 | You may obtain a copy of the License at 230 | 231 | http://www.apache.org/licenses/LICENSE-2.0 232 | 233 | Unless required by applicable law or agreed to in writing, software 234 | distributed under the License is distributed on an "AS IS" BASIS, 235 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 236 | See the License for the specific language governing permissions and 237 | limitations under the License. 238 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # `parse-generics` 3 | 4 | This repository contains several pieces related to the proposed [RFC #1583]: 5 | 6 | - `parse-generics-poc` - a proof-of-concept implementation of the RFC. 7 | - `parse-generics-shim` - a "polyfill" shim containing an implementation of a subset of the RFC in stable `macro_rules!`. 8 | - `parse-macros` - a crate containing higher-level parsing macros built on top of `parse-generics-shim`. 9 | 10 | A very basic example of using `parse-macros` in a crate, and then using *that* crate, is provided by the [`enum-as-str`](enum-as-str/) and [`enum-as-str-test`](enum-as-str-test/) crates. Further examples can be found by looking at the `parse-macro` crate's `tests` directory. Specifically: 11 | 12 | - [`derive_clone.rs`](parse-macros/tests/derive_clone.rs) - a stable implementation of the built-in `Clone` derivation compiler plugin. 13 | - [`derive_partial_ord.rs`](parse-macros/tests/derive_partial_ord.rs) - a stable implementation of the built-in `PartialOrd` derivation compiler plugin. I was once *assured* this was impossible by a member of the core team. 14 | - [`derive_serialize.rs`](parse-macros/tests/derive_serialize.rs) - a stable derivation macro for [`serde`]'s `Serialize` trait. Does not support attributes (*e.g.* custom field names). 15 | - [`reflect.rs`](parse-macros/tests/reflect.rs) - a *very* minimal compile-time reflection derivation macro. Progress is blocked on not being able to define generic constants/statics, not on parsing or generation complexity. 16 | 17 | **Links** 18 | 19 | * Latest Releases ([`parse-generics-poc`](https://crates.io/crates/parse-generics-poc), [`parse-generics-shim`](https://crates.io/crates/parse-generics-shim), [`parse-macros`](https://crates.io/crates/parse-macros)) 20 | * Latest Docs ([`parse-generics-poc`](https://danielkeep.github.io/rust-parse-generics/doc/parse_generics_poc/index.html), [`parse-generics-shim`](https://danielkeep.github.io/rust-parse-generics/doc/parse_generics_shim/index.html), [`parse-macros`](https://danielkeep.github.io/rust-parse-generics/doc/parse_macros/index.html)) 21 | * [Repository](https://github.com/DanielKeep/rust-parse-generics) 22 | 23 | ## Supporting RFC #1583 24 | 25 | The core team currently feels uneasy about accepting [RFC #1583], due to its complexity and the lack of demonstrable support for being able to correctly process generics and `where` clauses in macros. 26 | 27 | If you would like to see it accepted, using the `parse-generics-shim` crate (and supporting its `use-parse-generics-poc` feature) will help demonstrate the desire for these macros to be accepted into the compiler. 28 | 29 | [RFC #1583]: https://github.com/rust-lang/rfcs/pull/1583 30 | 31 | ## License 32 | 33 | Licensed under either of 34 | 35 | * MIT license (see [LICENSE](LICENSE) or ) 36 | * Apache License, Version 2.0 (see [LICENSE](LICENSE) or ) 37 | 38 | at your option. 39 | 40 | ### Contribution 41 | 42 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions. 43 | -------------------------------------------------------------------------------- /doc-pkg/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /doc-pkg/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "doc-pkg" 3 | version = "0.1.0" 4 | authors = ["Daniel Keep "] 5 | 6 | [dependencies] 7 | parse-generics-poc = { path = "../parse-generics-poc" } 8 | parse-generics-shim = { path = "../parse-generics-shim" } 9 | parse-macros = { path = "../parse-macros" } 10 | 11 | [lib] 12 | name = "doc" 13 | path = "src.rs" 14 | doc = false 15 | -------------------------------------------------------------------------------- /doc-pkg/src.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielKeep/rust-parse-generics/48248a2de844772c0fd76cbaa24492e4dfc146af/doc-pkg/src.rs -------------------------------------------------------------------------------- /enum-as-str-test/.gitignore: -------------------------------------------------------------------------------- 1 | /local 2 | /target 3 | /Cargo.lock 4 | -------------------------------------------------------------------------------- /enum-as-str-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enum-as-str-test" 3 | version = "0.1.0" 4 | authors = ["Daniel Keep "] 5 | 6 | [features] 7 | use-parse-generics-poc = [ 8 | "enum-as-str/use-parse-generics-poc", 9 | "parse-generics-poc", 10 | "parse-macros/use-parse-generics-poc", 11 | ] 12 | 13 | [dependencies] 14 | custom_derive = "0.1.5" 15 | enum-as-str = { version = "0.1.0", path = "../enum-as-str" } 16 | parse-generics-poc = { version = "0.1.0", optional = true, path = "../parse-generics-poc" } 17 | parse-generics-shim = "0.1.0" 18 | parse-macros = "0.1.0" 19 | -------------------------------------------------------------------------------- /enum-as-str-test/src/main.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 11 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 12 | #[macro_use] extern crate custom_derive; 13 | #[macro_use] extern crate enum_as_str; 14 | #[macro_use] extern crate parse_generics_shim; 15 | #[macro_use] extern crate parse_macros; 16 | 17 | custom_derive! { 18 | #[allow(dead_code)] 19 | #[derive(enum_as_str)] 20 | enum Dagashi { 21 | Umaibou, 22 | PotatoFries, 23 | CoffeeMilk, 24 | YoungDonuts, 25 | KinakoBou, 26 | NamaikiBeer, 27 | FueRamune, 28 | Menko, 29 | } 30 | } 31 | 32 | fn main() { 33 | println!("{}", Dagashi::FueRamune.as_str()); 34 | } 35 | -------------------------------------------------------------------------------- /enum-as-str/.gitignore: -------------------------------------------------------------------------------- 1 | /local 2 | /target 3 | /Cargo.lock 4 | -------------------------------------------------------------------------------- /enum-as-str/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enum-as-str" 3 | version = "0.1.0" 4 | authors = ["Daniel Keep "] 5 | 6 | [features] 7 | use-parse-generics-poc = [ 8 | "parse-generics-poc", 9 | "parse-macros/use-parse-generics-poc", 10 | ] 11 | 12 | [dependencies] 13 | parse-generics-poc = { version = "0.1.0", optional = true } 14 | parse-macros = "0.1.0" 15 | -------------------------------------------------------------------------------- /enum-as-str/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[macro_export] 11 | macro_rules! enum_as_str { 12 | (() $($body:tt)*) => { 13 | enum_as_str! { (as_str) $($body)* } 14 | }; 15 | 16 | (($fn_name:ident) $($body:tt)*) => { 17 | parse_enum! { then enum_as_str! { @with_enum $fn_name, }, $($body)* } 18 | }; 19 | 20 | (@as_item $i:item) => { $i }; 21 | 22 | ( 23 | @with_enum 24 | $fn_name:ident, 25 | enum { 26 | attrs: $_attrs:tt, 27 | vis: $_vis:tt, 28 | name: $name:ident, 29 | generics: { 30 | constr: [ $($constr:tt)* ], 31 | params: [ $($params:tt)* ], 32 | $($_generics:tt)* 33 | }, 34 | where: { 35 | clause: [$($clause:tt)*], 36 | preds: $_preds:tt, 37 | }, 38 | variants: [ 39 | $( 40 | { 41 | ord: $_ord:tt, 42 | attrs: $_vattrs:tt, 43 | kind: unitary, 44 | name: $vname:ident, 45 | fields: [], 46 | num_fields: $_vnum_fields:tt, 47 | }, 48 | )* 49 | ], 50 | num_variants: $_num_variants:tt, 51 | } 52 | ) => { 53 | enum_as_str! { 54 | @as_item 55 | impl<$($constr)*> $name<$($params)*> $($clause)* { 56 | pub fn $fn_name(&self) -> &'static str { 57 | match *self { 58 | $( 59 | $name::$vname => stringify!($vname), 60 | )* 61 | } 62 | } 63 | } 64 | } 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /parse-generics-poc/.gitignore: -------------------------------------------------------------------------------- 1 | /local 2 | /target 3 | /Cargo.lock 4 | -------------------------------------------------------------------------------- /parse-generics-poc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parse-generics-poc" 3 | version = "0.1.2" 4 | authors = ["Daniel Keep "] 5 | 6 | description = "A proof-of-concept implementation of the proposed RFC #1583; provides macros for parsing generics and where clauses. Note: requires a compatible nightly compiler. For a stable alternative, see the parse-generics-shim crate." 7 | repository = "https://github.com/DanielKeep/rust-parse-generics" 8 | documentation = "https://danielkeep.github.io/rust-parse-generics/doc/parse_generics_poc/index.html" 9 | keywords = ["macro", "parse", "generics", "where", "plugin"] 10 | license = "MIT/Apache-2.0" 11 | 12 | [lib] 13 | name = "parse_generics_poc" 14 | plugin = true 15 | 16 | [dev-dependencies] 17 | custom_derive = "0.1.4" 18 | -------------------------------------------------------------------------------- /parse-generics-poc/tests/derive_clone_copy.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![feature(plugin)] 11 | #![plugin(parse_generics_poc)] 12 | #[macro_use] extern crate custom_derive; 13 | 14 | macro_rules! CloneCopy { 15 | ( 16 | () $(pub)* enum $name:ident $($tail:tt)* 17 | ) => { 18 | parse_generics! { 19 | { constr, params, ltimes, tnames }, 20 | then CloneCopy! { @with_generics (enum $name), }, 21 | $($tail)* 22 | } 23 | }; 24 | 25 | ( 26 | () $(pub)* struct $name:ident $($tail:tt)* 27 | ) => { 28 | parse_generics! { 29 | { constr, params, ltimes, tnames }, 30 | then CloneCopy! { @with_generics (struct $name), }, 31 | $($tail)* 32 | } 33 | }; 34 | 35 | ( 36 | @with_generics 37 | $prefix:tt, $generics:tt, 38 | ($($body:tt)*) 39 | $($tail:tt)* 40 | ) => { 41 | parse_where! { 42 | { preds }, then CloneCopy! { @expand $prefix, $generics, }, 43 | $($tail)* ($($body)*) 44 | } 45 | }; 46 | 47 | ( 48 | @with_generics 49 | $prefix:tt, $generics:tt, 50 | $($tail:tt)* 51 | ) => { 52 | parse_where! { 53 | { preds }, then CloneCopy! { @expand $prefix, $generics, }, 54 | $($tail)* 55 | } 56 | }; 57 | 58 | ( 59 | @expand ($_kind:tt $name:ident), 60 | { 61 | constr: [$($constr:tt)*], 62 | params: [$($params:tt)*], 63 | ltimes: $_ltimes:tt, 64 | tnames: [], 65 | }, 66 | { 67 | preds: [], 68 | }, 69 | $($_tail:tt)* 70 | ) => { 71 | CloneCopy! { 72 | @as_item 73 | impl<$($constr)*> Clone for $name<$($params)*> { 74 | fn clone(&self) -> Self { 75 | *self 76 | } 77 | } 78 | } 79 | }; 80 | 81 | ( 82 | @expand ($_kind:tt $name:ident), 83 | { 84 | constr: [$($constr:tt)*], 85 | params: [$($params:tt)*], 86 | ltimes: $_ltimes:tt, 87 | tnames: [$($tnames:ident,)*], 88 | }, 89 | { 90 | preds: [$($preds:tt)*] 91 | $($_more_preds:tt)* 92 | }, 93 | $($_tail:tt)* 94 | ) => { 95 | CloneCopy! { 96 | @as_item 97 | impl<$($constr)*> Clone for $name<$($params)*> 98 | where $($tnames: Copy,)* $($preds)* { 99 | fn clone(&self) -> Self { 100 | *self 101 | } 102 | } 103 | } 104 | }; 105 | 106 | (@as_item $i:item) => { $i }; 107 | } 108 | 109 | custom_derive! { 110 | #[derive(Copy, CloneCopy, Eq, PartialEq, Debug)] 111 | struct Type0(u32); 112 | } 113 | 114 | #[test] 115 | fn test_type_0() { 116 | let v = Type0(42); 117 | let (a, b) = (v, v); 118 | assert_eq!(a, b); 119 | } 120 | 121 | custom_derive! { 122 | #[derive(Copy, CloneCopy, Eq, PartialEq, Debug)] 123 | struct Type1 { value: T } 124 | } 125 | 126 | #[test] 127 | fn test_type_1() { 128 | let v = Type1 { value: 42 }; 129 | let (a, b) = (v, v); 130 | assert_eq!(a, b); 131 | } 132 | 133 | custom_derive! { 134 | #[derive(Copy, CloneCopy, Eq, PartialEq, Debug)] 135 | enum Type2 where T: Ord { A(T) } 136 | } 137 | 138 | #[test] 139 | fn test_type_2() { 140 | let v = Type2::A(42); 141 | let (a, b) = (v, v); 142 | assert_eq!(a, b); 143 | } 144 | -------------------------------------------------------------------------------- /parse-generics-poc/tests/derive_iterator.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![feature(plugin)] 11 | #![plugin(parse_generics_poc)] 12 | #[macro_use] extern crate custom_derive; 13 | 14 | use std::iter::once; 15 | use std::marker::PhantomData; 16 | 17 | macro_rules! Iterator { 18 | ( 19 | () $(pub)* struct $name:ident $($tail:tt)* 20 | ) => { 21 | parse_generics! { 22 | { constr, params, ltimes, tnames }, 23 | then Iterator!(@with_generics () struct $name,), 24 | $($tail)* 25 | } 26 | }; 27 | 28 | ( 29 | @with_generics 30 | () struct $name:ident, 31 | $generics:tt, 32 | ($($body:tt)*) 33 | $($tail:tt)* 34 | ) => { 35 | parse_where! { 36 | { preds }, then Iterator!(@with_where () struct $name, $generics,), 37 | $($tail)* ($($body)*) 38 | } 39 | }; 40 | 41 | ( 42 | @with_where 43 | () struct $name:ident, 44 | $generics:tt, 45 | $preds:tt, 46 | ; ($(pub)* $fty:ty) 47 | ) => { 48 | Iterator! { 49 | @with_where 50 | () struct $name, 51 | $generics, 52 | $preds, 53 | ; ($fty,) 54 | } 55 | }; 56 | 57 | ( 58 | @with_where 59 | () struct $name:ident, 60 | { 61 | constr: [$($constr:tt)*], 62 | params: [$($params:tt)*], 63 | $($_generics_tail:tt)* 64 | }, 65 | { 66 | preds: [$($preds:tt)*], 67 | }, 68 | ; ($(pub)* $fty:ty, $(PhantomData<$_phtys:ty>),* $(,)*) 69 | ) => { 70 | Iterator! { 71 | @as_items 72 | impl<$($constr)*> Iterator for $name<$($params)*> 73 | where $fty: Iterator, $($preds)* { 74 | type Item = <$fty as Iterator>::Item; 75 | fn next(&mut self) -> Option { 76 | Iterator::next(&mut self.0) 77 | } 78 | fn size_hint(&self) -> (usize, Option) { 79 | Iterator::size_hint(&self.0) 80 | } 81 | } 82 | } 83 | }; 84 | 85 | (@as_items $($its:item)*) => { $($its)* }; 86 | } 87 | 88 | custom_derive! { 89 | #[derive(Iterator)] 90 | struct IterA(Box>); 91 | } 92 | 93 | #[test] 94 | fn test_iter_a() { 95 | let mut it = IterA(Box::new(once("upon a time"))); 96 | assert_eq!(it.next(), Some("upon a time")); 97 | assert_eq!(it.next(), None); 98 | } 99 | 100 | custom_derive! { 101 | #[derive(Iterator)] 102 | struct IterB<'a>(Box + 'a>); 103 | } 104 | 105 | #[test] 106 | fn test_iter_b() { 107 | let mut it = IterB::<'static>(Box::new(once("upon a time"))); 108 | assert_eq!(it.next(), Some("upon a time")); 109 | assert_eq!(it.next(), None); 110 | } 111 | 112 | custom_derive! { 113 | #[derive(Iterator)] 114 | struct IterC<'a, T: ?Sized + 'a>(Box + 'a>); 115 | } 116 | 117 | #[test] 118 | fn test_iter_c() { 119 | let mut it = IterC::<'static, str>(Box::new(once("upon a time"))); 120 | assert_eq!(it.next(), Some("upon a time")); 121 | assert_eq!(it.next(), None); 122 | } 123 | 124 | custom_derive! { 125 | #[derive(Iterator)] 126 | struct IterD<'a, T: ?Sized + 'a>(Box + 'a>) 127 | where T: Copy; 128 | } 129 | 130 | #[test] 131 | fn test_iter_d() { 132 | const S: &'static &'static str = &"times in our lives"; 133 | let mut it = IterD(Box::new(once(S))); 134 | assert_eq!(it.next(), Some(&"times in our lives")); 135 | assert_eq!(it.next(), None); 136 | } 137 | 138 | custom_derive! { 139 | #[derive(Iterator)] 140 | struct IterE(Box>, PhantomData) 141 | where T: Copy + Clone; 142 | } 143 | 144 | #[test] 145 | fn test_iter_e() { 146 | const S: &'static &'static str = &"times in our lives"; 147 | let mut it = IterE(Box::new(once(S)), PhantomData); 148 | assert_eq!(it.next(), Some(&"times in our lives")); 149 | assert_eq!(it.next(), None); 150 | } 151 | 152 | custom_derive! { 153 | #[derive(Iterator)] 154 | struct IterF(I); 155 | } 156 | 157 | #[test] 158 | fn test_iter_f() { 159 | let it = IterF(once("you pop")); 160 | for e in it { 161 | assert!(e != "stop"); 162 | } 163 | } 164 | 165 | custom_derive! { 166 | #[derive(Iterator)] 167 | struct IterG(I) where I: Iterator; 168 | } 169 | 170 | #[test] 171 | fn test_iter_g() { 172 | let it = IterG(once("you pop")); 173 | for e in it { 174 | assert!(e != "stop"); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /parse-generics-poc/tests/simple.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![feature(plugin)] 11 | #![plugin(parse_generics_poc)] 12 | 13 | macro_rules! assert_eq_str { 14 | ($left:expr, $right:expr) => { 15 | assert_eq!($left.replace("\n", " "), $right.replace("\n", " ")) 16 | }; 17 | } 18 | 19 | #[test] 20 | fn test_simple() { 21 | assert_eq_str!( 22 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(),), 23 | "{ \ 24 | constr : [ ] , \ 25 | params : [ ] , \ 26 | ltimes : [ ] , \ 27 | tnames : [ ] , \ 28 | } ," 29 | ); 30 | 31 | assert_eq_str!( 32 | parse_generics!({ .. }, then stringify!(),), 33 | "{ \ 34 | constr : [ ] , \ 35 | params : [ ] , \ 36 | ltimes : [ ] , \ 37 | tnames : [ ] , \ 38 | .. \ 39 | } ," 40 | ); 41 | 42 | assert_eq_str!( 43 | parse_generics!({ params, mrtnames?, tnames?, bunnies? }, then stringify!(),), 44 | "{ \ 45 | params : [ ] , \ 46 | tnames : [ ] , \ 47 | } ," 48 | ); 49 | 50 | assert_eq_str!( 51 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(W),), 52 | "W { \ 53 | constr : [ ] , \ 54 | params : [ ] , \ 55 | ltimes : [ ] , \ 56 | tnames : [ ] , \ 57 | } ," 58 | ); 59 | 60 | assert_eq_str!( 61 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), <>), 62 | "{ \ 63 | constr : [ ] , \ 64 | params : [ ] , \ 65 | ltimes : [ ] , \ 66 | tnames : [ ] , \ 67 | } ," 68 | ); 69 | 70 | assert_eq_str!( 71 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 72 | "{ \ 73 | constr : [ ] , \ 74 | params : [ ] , \ 75 | ltimes : [ ] , \ 76 | tnames : [ ] , \ 77 | } , X" 78 | ); 79 | 80 | assert_eq_str!( 81 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), <> X), 82 | "{ \ 83 | constr : [ ] , \ 84 | params : [ ] , \ 85 | ltimes : [ ] , \ 86 | tnames : [ ] , \ 87 | } , X" 88 | ); 89 | 90 | assert_eq_str!( 91 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 'a X), 92 | "{ \ 93 | constr : [ ] , \ 94 | params : [ ] , \ 95 | ltimes : [ ] , \ 96 | tnames : [ ] , \ 97 | } , 'a X" 98 | ); 99 | 100 | assert_eq_str!( 101 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), <'a> X), 102 | "{ \ 103 | constr : [ 'a , ] , \ 104 | params : [ 'a , ] , \ 105 | ltimes : [ 'a , ] , \ 106 | tnames : [ ] , \ 107 | } , X" 108 | ); 109 | 110 | assert_eq_str!( 111 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), <'a, 'b> X), 112 | "{ \ 113 | constr : [ 'a , 'b , ] , \ 114 | params : [ 'a , 'b , ] , \ 115 | ltimes : [ 'a , 'b , ] , \ 116 | tnames : [ ] , \ 117 | } , X" 118 | ); 119 | 120 | assert_eq_str!( 121 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 122 | "{ \ 123 | constr : [ T , ] , \ 124 | params : [ T , ] , \ 125 | ltimes : [ ] , \ 126 | tnames : [ T , ] , \ 127 | } , X" 128 | ); 129 | 130 | assert_eq_str!( 131 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 132 | "{ \ 133 | constr : [ T , U , ] , \ 134 | params : [ T , U , ] , \ 135 | ltimes : [ ] , \ 136 | tnames : [ T , U , ] , \ 137 | } , X" 138 | ); 139 | 140 | assert_eq_str!( 141 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), <'a, 'b: 'a> X), 142 | "{ \ 143 | constr : [ 'a , 'b : 'a , ] , \ 144 | params : [ 'a , 'b , ] , \ 145 | ltimes : [ 'a , 'b , ] , \ 146 | tnames : [ ] , \ 147 | } , X" 148 | ); 149 | 150 | assert_eq_str!( 151 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), <'a, 'b: 'a + 'c> X), 152 | "{ \ 153 | constr : [ 'a , 'b : 'a + 'c , ] , \ 154 | params : [ 'a , 'b , ] , \ 155 | ltimes : [ 'a , 'b , ] , \ 156 | tnames : [ ] , \ 157 | } , X" 158 | ); 159 | 160 | assert_eq_str!( 161 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 162 | "{ \ 163 | constr : [ T : Copy , ] , \ 164 | params : [ T , ] , \ 165 | ltimes : [ ] , \ 166 | tnames : [ T , ] , \ 167 | } , X" 168 | ); 169 | 170 | assert_eq_str!( 171 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 172 | "{ \ 173 | constr : [ T : std :: marker :: Copy , ] , \ 174 | params : [ T , ] , \ 175 | ltimes : [ ] , \ 176 | tnames : [ T , ] , \ 177 | } , X" 178 | ); 179 | 180 | assert_eq_str!( 181 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 182 | "{ \ 183 | constr : [ T : :: std :: marker :: Copy , ] , \ 184 | params : [ T , ] , \ 185 | ltimes : [ ] , \ 186 | tnames : [ T , ] , \ 187 | } , X" 188 | ); 189 | 190 | assert_eq_str!( 191 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 192 | "{ \ 193 | constr : [ T : 'a , ] , \ 194 | params : [ T , ] , \ 195 | ltimes : [ ] , \ 196 | tnames : [ T , ] , \ 197 | } , X" 198 | ); 199 | 200 | assert_eq_str!( 201 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 202 | "{ \ 203 | constr : [ T : 'a + Copy + Clone , ] , \ 204 | params : [ T , ] , \ 205 | ltimes : [ ] , \ 206 | tnames : [ T , ] , \ 207 | } , X" 208 | ); 209 | 210 | assert_eq_str!( 211 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), X), 212 | "{ \ 213 | constr : [ T : 'a + 'b + Copy + Clone , ] , \ 214 | params : [ T , ] , \ 215 | ltimes : [ ] , \ 216 | tnames : [ T , ] , \ 217 | } , X" 218 | ); 219 | 220 | assert_eq_str!( 221 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 222 | Fn()> X), 223 | "{ \ 224 | constr : [ T : 'a + 'b + Copy + Clone \ 225 | + for < 'c , 'd : 'e > Fn ( ) , ] , \ 226 | params : [ T , ] , \ 227 | ltimes : [ ] , \ 228 | tnames : [ T , ] , \ 229 | } , X" 230 | ); 231 | 232 | assert_eq_str!( 233 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 234 | Fn() -> &'c i32> X), 235 | "{ \ 236 | constr : [ T : 'a + 'b + Copy + Clone \ 237 | + for < 'c , 'd : 'e > Fn ( ) -> &'c i32 , ] , \ 238 | params : [ T , ] , \ 239 | ltimes : [ ] , \ 240 | tnames : [ T , ] , \ 241 | } , X" 242 | ); 243 | 244 | assert_eq_str!( 245 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 246 | Fn(&'c i32)> X), 247 | "{ \ 248 | constr : [ T : 'a + 'b + Copy + Clone \ 249 | + for < 'c , 'd : 'e > Fn ( &'c i32 ) , ] , \ 250 | params : [ T , ] , \ 251 | ltimes : [ ] , \ 252 | tnames : [ T , ] , \ 253 | } , X" 254 | ); 255 | 256 | assert_eq_str!( 257 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 258 | Fn(&'c i32) -> &'d ()> X), 259 | "{ \ 260 | constr : [ T : 'a + 'b + Copy + Clone \ 261 | + for < 'c , 'd : 'e > Fn ( &'c i32 ) -> &'d () , ] , \ 262 | params : [ T , ] , \ 263 | ltimes : [ ] , \ 264 | tnames : [ T , ] , \ 265 | } , X" 266 | ); 267 | 268 | assert_eq_str!( 269 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 270 | <'a, 'b, 'd, T: 'a + 'b + Copy + Clone + for<'c, 'd: 'e> Fn(&'c i32) -> &'d ()> X), 271 | "{ \ 272 | constr : [ 'a , 'b , 'd , T : 'a + 'b + Copy + Clone \ 273 | + for < 'c , 'd : 'e > Fn ( &'c i32 ) -> &'d () , ] , \ 274 | params : [ 'a , 'b , 'd , T , ] , \ 275 | ltimes : [ 'a , 'b , 'd , ] , \ 276 | tnames : [ T , ] , \ 277 | } , X" 278 | ); 279 | 280 | assert_eq_str!( 281 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 282 | Copy> X), 283 | "{ \ 284 | constr : [ T : Copy , ] , \ 285 | params : [ T , ] , \ 286 | ltimes : [ ] , \ 287 | tnames : [ T , ] , \ 288 | } , X" 289 | ); 290 | 291 | assert_eq_str!( 292 | parse_generics!({ constr, params, ltimes, tnames }, then stringify!(), 293 | > X), 294 | "{ \ 295 | constr : [ T : :: std :: convert :: Into < String > , ] , \ 296 | params : [ T , ] , \ 297 | ltimes : [ ] , \ 298 | tnames : [ T , ] , \ 299 | } , X" 300 | ); 301 | 302 | assert_eq_str!( 303 | parse_generics!({}, then stringify!(), <'a: 'b, T: U> X), 304 | "{ } , X" 305 | ); 306 | 307 | assert_eq_str!( 308 | parse_generics!({ constr }, then stringify!(), <'a: 'b, T: U> X), 309 | "{ \ 310 | constr : [ 'a : 'b , T : U , ] , \ 311 | } , X" 312 | ); 313 | 314 | assert_eq_str!( 315 | parse_generics!({ params }, then stringify!(), <'a: 'b, T: U> X), 316 | "{ \ 317 | params : [ 'a , T , ] , \ 318 | } , X" 319 | ); 320 | 321 | assert_eq_str!( 322 | parse_generics!({ ltimes }, then stringify!(), <'a: 'b, T: U> X), 323 | "{ \ 324 | ltimes : [ 'a , ] , \ 325 | } , X" 326 | ); 327 | 328 | assert_eq_str!( 329 | parse_generics!({ tnames }, then stringify!(), <'a: 'b, T: U> X), 330 | "{ \ 331 | tnames : [ T , ] , \ 332 | } , X" 333 | ); 334 | 335 | assert_eq_str!( 336 | parse_generics!({ constr, params }, then stringify!(), <'a: 'b, T: U> X), 337 | "{ \ 338 | constr : [ 'a : 'b , T : U , ] , \ 339 | params : [ 'a , T , ] , \ 340 | } , X" 341 | ); 342 | 343 | assert_eq_str!( 344 | parse_generics!({ params, constr }, then stringify!(), <'a: 'b, T: U> X), 345 | "{ \ 346 | params : [ 'a , T , ] , \ 347 | constr : [ 'a : 'b , T : U , ] , \ 348 | } , X" 349 | ); 350 | } 351 | 352 | #[test] 353 | fn test_simple_where() { 354 | assert_eq_str!( 355 | parse_where!({ clause, preds }, then stringify!(),), 356 | "{ clause : [ ] , preds : [ ] , } ," 357 | ); 358 | 359 | assert_eq_str!( 360 | parse_where!({ preds }, then stringify!(),), 361 | "{ preds : [ ] , } ," 362 | ); 363 | 364 | assert_eq_str!( 365 | parse_where!({ .. }, then stringify!(),), 366 | "{ clause : [ ] , preds : [ ] , .. } ," 367 | ); 368 | 369 | assert_eq_str!( 370 | parse_where!({ preds }, then stringify!(), X), 371 | "{ preds : [ ] , } , X" 372 | ); 373 | 374 | assert_eq_str!( 375 | parse_where!({ preds }, then stringify!(), {} X), 376 | "{ preds : [ ] , } , { } X" 377 | ); 378 | 379 | assert_eq_str!( 380 | parse_where!({ clause }, then stringify!(), where T: Copy {X}), 381 | "{ clause : [ where T : Copy , ] , } , { X }" 382 | ); 383 | 384 | assert_eq_str!( 385 | parse_where!({ preds }, then stringify!(), where T: Copy {X}), 386 | "{ preds : [ T : Copy , ] , } , { X }" 387 | ); 388 | 389 | assert_eq_str!( 390 | parse_where!({ preds }, then stringify!(), where T: Copy, {X}), 391 | "{ preds : [ T : Copy , ] , } , { X }" 392 | ); 393 | 394 | assert_eq_str!( 395 | parse_where!({ preds }, then stringify!(), where T: Copy; {X}), 396 | "{ preds : [ T : Copy , ] , } , ; { X }" 397 | ); 398 | 399 | assert_eq_str!( 400 | parse_where!({ preds }, then stringify!(), where for<'a> &'a str: Into {X}), 401 | "{ preds : [ for < 'a , > &'a str : Into < T > , ] , } , { X }" 402 | ); 403 | 404 | assert_eq_str!( 405 | parse_where!({ preds }, then stringify!(), 406 | where for<'a: 'b, 'b> &'a str: Into {X}), 407 | "{ \ 408 | preds : [ \ 409 | for < 'a : 'b , 'b , > &'a str : Into < T+ 'b > , \ 410 | ] , \ 411 | } , { X }" 412 | ); 413 | 414 | assert_eq_str!( 415 | parse_where!({ preds }, then stringify!(), 416 | where &'a str: Into, 'a: 'b, 'b: 'c + 'd {X}), 417 | "{ \ 418 | preds : [ \ 419 | &'a str : Into < T+ 'b > , \ 420 | 'a : 'b , \ 421 | 'b : 'c + 'd , \ 422 | ] , \ 423 | } , { X }" 424 | ); 425 | 426 | assert_eq_str!( 427 | parse_where!({}, then stringify!(), where T: Copy {X}), 428 | "{ } , { X }" 429 | ); 430 | } 431 | -------------------------------------------------------------------------------- /parse-generics-poc/tests/wrap_fn.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![feature(plugin)] 11 | #![plugin(parse_generics_poc)] 12 | 13 | use std::fmt::Display; 14 | 15 | macro_rules! wrap_fn { 16 | ( 17 | as $wrap_name:ident, 18 | fn $fn_name:ident $($tail:tt)* 19 | ) => { 20 | parse_generics! { 21 | { constr, params, ltimes, tnames }, 22 | then wrap_fn!(@expand $wrap_name, $fn_name,), 23 | $($tail)* 24 | } 25 | }; 26 | 27 | (@as_item $i:item) => { $i }; 28 | 29 | ( 30 | @expand 31 | $wrap_name:ident, 32 | $fn_name:ident, 33 | { 34 | constr: [$($constr:tt)*], 35 | params: [$($params:tt)*], 36 | $($_generics_tail:tt)* 37 | }, 38 | ( 39 | $($arg_pats:ident: $arg_tys:ty),* $(,)* 40 | ) 41 | $(-> $ret_ty:ty)* ; 42 | pre { $($pre:tt)* } 43 | post($res:ident) { $($post:tt)* } 44 | ) => { 45 | wrap_fn! { 46 | @as_item 47 | fn $wrap_name<$($constr)*>($($arg_pats: $arg_tys),*) $(-> $ret_ty)* { 48 | $($pre)* 49 | let $res = $fn_name::<$($params)*>($($arg_pats),*); 50 | $($post)* 51 | } 52 | } 53 | }; 54 | } 55 | 56 | wrap_fn! { 57 | as wrap_to_string, 58 | fn to_string(v: T) -> String; 59 | pre { 60 | let prefix = String::from("wrap:"); 61 | } 62 | post(result) { 63 | format!("{}{}", prefix, result) 64 | } 65 | } 66 | 67 | fn to_string(v: T) -> String { 68 | format!("{}", v) 69 | } 70 | 71 | #[test] 72 | fn test_wrap_fn() { 73 | assert_eq!(&*wrap_to_string(42i32), "wrap:42"); 74 | } 75 | 76 | trait Dummy<'a, T: ?Sized>: Sized { 77 | fn id(self) -> Self { self } 78 | } 79 | 80 | impl<'a> Dummy<'a, str> for &'a str {} 81 | 82 | fn id<'a, T: ?Sized, U: ::Dummy<'a, T>>(v: U) -> U { v.id() } 83 | 84 | wrap_fn! { 85 | as wrap_id, 86 | fn id<'a, T: ?Sized, U: ::Dummy<'a, T>>(v: U) -> U; 87 | pre {} 88 | post(result) { result } 89 | } 90 | 91 | #[test] 92 | fn test_wrap_fn_id() { 93 | assert_eq!(wrap_id("hi!"), "hi!"); 94 | } 95 | -------------------------------------------------------------------------------- /parse-generics-shim/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /parse-generics-shim/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parse-generics-shim" 3 | version = "0.1.2" 4 | authors = ["Daniel Keep "] 5 | 6 | description = "A stable shim for the proposed RFC #1583; provides macros for parsing generics and where clauses." 7 | repository = "https://github.com/DanielKeep/rust-parse-generics" 8 | documentation = "https://danielkeep.github.io/rust-parse-generics/doc/parse_generics_shim/index.html" 9 | keywords = ["macro", "parse", "generics", "where"] 10 | license = "MIT/Apache-2.0" 11 | 12 | [features] 13 | use-parse-generics-poc = ["parse-generics-poc"] 14 | 15 | [dependencies.parse-generics-poc] 16 | version = "0.1.0" 17 | optional = true 18 | path = "../parse-generics-poc" 19 | 20 | [dev-dependencies] 21 | rustc_version = "0.1.7" 22 | -------------------------------------------------------------------------------- /parse-generics-shim/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | /*! 11 | This crate provides stable, partial implementations of the `parse_generics!` and `parse_where!` macros proposed in [RFC #1583]. These macros serve two purposes: 12 | 13 | 1. They allow crate authors to use the macros in a limited capacity whether or not the RFC is accepted. 14 | 2. They demonstrate to the Rust core team that there is demand for this functionality. 15 | 3. They provide a migration path from the partial implementation to the full one, assuming the RFC does get accepted. 16 | 17 | Because these macros are implemented using `macro_rules!`, they have the following limitations: 18 | 19 | - In general, only lifetimes `'a` through `'z` are accepted. 20 | - Only a subset of the full output formats are supported. 21 | - They are significantly less efficient, and consume a non-trivial amount of the recursion limit. 22 | 23 | 36 | 45 | 46 | # Table of Contents 47 | 48 | - [`parse_generics_shim!`](#parse_generics_shim) 49 | - [`parse_where_shim!`](#parse_where_shim) 50 | - [Using `parse-generics-poc`](#using-parse-generics-poc) 51 | 52 | [RFC #1583]: https://github.com/rust-lang/rfcs/pull/1583 53 | 54 | ## `parse_generics_shim!` 55 | 56 | ```ignore 57 | macro_rules! parse_generics_shim { 58 | ( 59 | { $($fields:ident),+ }, 60 | then $callback_name:ident ! ( $($callback_args:tt)* ), 61 | $($code:tt)* 62 | ) => { ... }; 63 | } 64 | ``` 65 | 66 | Parses a generic parameter list (if present) from the start of `$($code:tt)*`, expanding to the parsed information plus the unconsumed tokens *after* the parameter list. The general form of the expansion is: 67 | 68 | ```ignore 69 | $callback_name! { 70 | $($callback_args)* 71 | { 72 | $( 73 | $fields: [ .. ], 74 | )+ 75 | }, 76 | $($tail)* 77 | } 78 | ``` 79 | 80 | ### Callback 81 | 82 | `$callback_name` and `$callback_args` specify the macro to invoke with the result of parsing. Note that `$callback_args` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`. 83 | 84 | ### Fields 85 | 86 | `$fields` indicates which pieces of information you want in the expansion. The available fields are: 87 | 88 | - `constr` - comma-terminated list of generic parameters plus their constraints. 89 | - `params` - comma-terminated list of generic parameter names (both lifetimes and types). 90 | - `ltimes` - comma-terminated list of generic lifetime names. 91 | - `tnames` - comma-terminated list of generic type names. 92 | 93 | The shim *only* supports the following combinations: 94 | 95 | - `{ constr, params, ltimes, tnames }` 96 | - `{ constr }` 97 | - `{ .. }` 98 | 99 | The fields will appear in the output in the same order they appear in the input. One special case is `{ .. }` which causes *all* fields to be emitted, followed by a literal `..` token. 100 | 101 | **Warning**: there is explicitly *no* guarantee that the list of fields will stay the same over time. As such, it is **strongly** recommended that you never directly match the `..` token after the fields. Instead, you should use the following construct: 102 | 103 | ```ignore 104 | macro_rules! match_output { 105 | ( 106 | { 107 | // Match the fields you care about. 108 | constr: $constr:tt, 109 | params: [ $($params:tt,)* ], 110 | 111 | // Ignore the rest; *never* explicitly match `..`! 112 | $($_fields:tt)* 113 | }, 114 | 115 | $($tail:tt)* 116 | ) => { ... }; 117 | } 118 | ``` 119 | 120 | ### Code 121 | 122 | `$code` is the actual source code to be parsed. If it starts with `<`, the macro will parse a generic parameter list. If it *does not* start with `<`, the macro will proceed as though the input started with an empty generic parameter list (*i.e.* `<>`). 123 | 124 | ### Examples 125 | 126 | The following show how the various invocation forms affect the output: 127 | 128 | ```rust 129 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 130 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 131 | # #[macro_use] extern crate parse_generics_shim; 132 | # fn main() { 133 | # assert_eq!( ( 134 | parse_generics_shim! { 135 | { constr, params, ltimes, tnames }, 136 | then stringify!(output:), 137 | <'a, T, U: 'a + Copy> X 138 | } 139 | 140 | // Expands to: 141 | # /* 142 | stringify!( 143 | # */ 144 | # ).replace(char::is_whitespace, "") , " 145 | output: { 146 | constr: [ 'a, T, U: 'a + Copy, ], 147 | params: [ 'a, T, U, ], 148 | ltimes: [ 'a, ], 149 | tnames: [ T, U, ], 150 | }, 151 | X 152 | # ".replace(char::is_whitespace, "")); /* 153 | ) 154 | # */ } 155 | ``` 156 | 157 | ```rust 158 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 159 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 160 | # #[macro_use] extern crate parse_generics_shim; 161 | # fn main() { 162 | # assert_eq!( ( 163 | parse_generics_shim! { 164 | { constr }, 165 | then stringify!(output:), 166 | <'a, T, U: 'a + Copy> X 167 | } 168 | 169 | // Expands to: 170 | # /* 171 | stringify!( 172 | # */ 173 | # ).replace(char::is_whitespace, "") , " 174 | output: { 175 | constr: [ 'a, T, U: 'a + Copy, ], 176 | }, 177 | X 178 | # ".replace(char::is_whitespace, "")); /* 179 | ) 180 | # */ } 181 | ``` 182 | 183 | ```rust 184 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 185 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 186 | # #[macro_use] extern crate parse_generics_shim; 187 | # fn main() { 188 | # assert_eq!( ( 189 | parse_generics_shim! { 190 | { .. }, 191 | then stringify!(output:), 192 | <'a, T, U: 'a + Copy> X 193 | } 194 | 195 | // Expands to: 196 | # /* 197 | stringify!( 198 | # */ 199 | # ).replace(char::is_whitespace, "") , " 200 | output: { 201 | constr: [ 'a, T, U: 'a + Copy, ], 202 | params: [ 'a, T, U, ], 203 | ltimes: [ 'a, ], 204 | tnames: [ T, U, ], 205 | .. 206 | }, 207 | X 208 | # ".replace(char::is_whitespace, "")); /* 209 | ) 210 | # */ } 211 | ``` 212 | 213 | The input does not *have* to start with a generic parameter list. Note that both of the invocations below expand to the same result: 214 | 215 | ```rust 216 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 217 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 218 | # #[macro_use] extern crate parse_generics_shim; 219 | # fn main() { 220 | # assert_eq!( ( 221 | parse_generics_shim! { 222 | { constr, params, ltimes, tnames }, 223 | then stringify!(output:), 224 | <> X 225 | } 226 | 227 | // Expands to: 228 | # /* 229 | stringify!( 230 | # */ 231 | # ).replace(char::is_whitespace, "") , " 232 | output: { 233 | constr: [], 234 | params: [], 235 | ltimes: [], 236 | tnames: [], 237 | }, 238 | X 239 | # ".replace(char::is_whitespace, "")); /* 240 | ) 241 | # */ } 242 | ``` 243 | 244 | ```rust 245 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 246 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 247 | # #[macro_use] extern crate parse_generics_shim; 248 | # fn main() { 249 | # assert_eq!( ( 250 | parse_generics_shim! { 251 | { constr, params, ltimes, tnames }, 252 | then stringify!(output:), 253 | X 254 | } 255 | 256 | // Expands to: 257 | # /* 258 | stringify!( 259 | # */ 260 | # ).replace(char::is_whitespace, "") , " 261 | output: { 262 | constr: [], 263 | params: [], 264 | ltimes: [], 265 | tnames: [], 266 | }, 267 | X 268 | # ".replace(char::is_whitespace, "")); /* 269 | ) 270 | # */ } 271 | ``` 272 | 273 | ## `parse_where_shim!` 274 | 275 | ```ignore 276 | macro_rules! parse_where_shim { 277 | ( 278 | { $($fields:ident),+ }, 279 | then $callback_name:ident ! ( $($callback_args:tt)* ), 280 | $($code:tt)* 281 | ) => { ... }; 282 | } 283 | ``` 284 | 285 | Parses a `where` clause (if present) from the start of `$($code:tt)*`, expanding to the parsed information plus the unconsumed tokens *after* the clause. The general form of the expansion is: 286 | 287 | ```ignore 288 | $callback_name! { 289 | $($callback_args)* 290 | { 291 | $( 292 | $fields: [ .. ], 293 | )+ 294 | }, 295 | $($tail)* 296 | } 297 | ``` 298 | 299 | ### Callback 300 | 301 | `$callback_name` and `$callback_args` specify the macro to invoke with the result of parsing. Note that `$callback_args` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`. 302 | 303 | ### Fields 304 | 305 | `$fields` indicates which pieces of information you want in the expansion. The available fields are: 306 | 307 | - `clause` - comma-terminated clause *including* the `where` keyword. If there is no clause, the `where` keyword is omitted. Use this if you simply wish to pass a `where` clause through unmodified. 308 | - `preds` - comma-terminated list of predicates. Use this if you wish to modify or append to the predicates. 309 | 310 | The shim *only* supports the following combinations: 311 | 312 | - `{ clause, preds }` 313 | - `{ preds }` 314 | - `{ .. }` 315 | 316 | The fields will appear in the output in the same order they appear in the input. One special case is `{ .. }` which causes *all* fields to be emitted, followed by a literal `..` token. 317 | 318 | **Warning**: there is explicitly *no* guarantee that the list of fields will stay the same over time. As such, it is **strongly** recommended that you never directly match the `..` token after the fields. Instead, you should use the following construct: 319 | 320 | ```ignore 321 | macro_rules! match_output { 322 | ( 323 | { 324 | // Match the fields you care about. 325 | clause: [ $($clause:tt)* ], 326 | 327 | // Ignore the rest; *never* explicitly match `..`! 328 | $($_fields:tt)* 329 | }, 330 | 331 | $($tail:tt)* 332 | ) => { ... }; 333 | } 334 | ``` 335 | 336 | ### Code 337 | 338 | `$code` is the actual source code to be parsed. If it starts with `where`, the macro will parse a `where` clause, stopping when it encounters any of the following: `;`, `{`, or `=`. If it *does not* start with `where`, the macro will expand with an empty predicate list. 339 | 340 | ### Examples 341 | 342 | The following show how the various invocation forms affect the output: 343 | 344 | ```rust 345 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 346 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 347 | # #[macro_use] extern crate parse_generics_shim; 348 | # fn main() { 349 | # assert_eq!( ( 350 | parse_where_shim! { 351 | { preds }, 352 | then stringify!(output:), 353 | where 354 | 'a: 'b, 355 | T: 'a + Copy, 356 | for<'c> U: Foo<'c>, 357 | { struct fields... } 358 | } 359 | 360 | // Expands to: 361 | # /* 362 | stringify!( 363 | # */ 364 | # ).replace(char::is_whitespace, "") , " 365 | output: { 366 | preds: [ 'a: 'b, T: 'a + Copy, for<'c,> U: Foo<'c>, ], 367 | }, 368 | { struct fields... } 369 | # ".replace(char::is_whitespace, "")); /* 370 | ) 371 | # */ } 372 | ``` 373 | 374 | ```rust 375 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 376 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 377 | # #[macro_use] extern crate parse_generics_shim; 378 | # fn main() { 379 | # assert_eq!( ( 380 | parse_where_shim! { 381 | { .. }, 382 | then stringify!(output:), 383 | where 384 | 'a: 'b, 385 | T: 'a + Copy, 386 | for<'c> U: Foo<'c>, 387 | { struct fields... } 388 | } 389 | 390 | // Expands to: 391 | # /* 392 | stringify!( 393 | # */ 394 | # ).replace(char::is_whitespace, "") , " 395 | output: { 396 | clause: [ where 'a: 'b, T: 'a + Copy, for<'c,> U: Foo<'c>, ], 397 | preds: [ 'a: 'b, T: 'a + Copy, for<'c,> U: Foo<'c>, ], 398 | .. 399 | }, 400 | { struct fields... } 401 | # ".replace(char::is_whitespace, "")); /* 402 | ) 403 | # */ } 404 | ``` 405 | 406 | The input does not *have* to start with a `where` clause: 407 | 408 | ```rust 409 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 410 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 411 | # #[macro_use] extern crate parse_generics_shim; 412 | # fn main() { 413 | # assert_eq!( ( 414 | parse_where_shim! { 415 | { preds }, 416 | then stringify!(output:), 417 | ; X 418 | } 419 | 420 | // Expands to: 421 | # /* 422 | stringify!( 423 | # */ 424 | # ).replace(char::is_whitespace, "") , " 425 | output: { 426 | preds: [], 427 | }, 428 | ; X 429 | # ".replace(char::is_whitespace, "")); /* 430 | ) 431 | # */ } 432 | ``` 433 | 434 | ## Using `parse-generics-poc` 435 | 436 | ### For Crate Authors 437 | 438 | Add the following to your `Cargo.toml` manifest: 439 | 440 | ```toml 441 | [features] 442 | use-parse-generics-poc = [ 443 | "parse-generics-poc", 444 | "parse-generics-shim/use-parse-generics-poc", 445 | ] 446 | 447 | [dependencies] 448 | parse-generics-poc = { version = "0.1.0", optional = true } 449 | parse-generics-shim = "0.1.0" 450 | ``` 451 | 452 | This allows your users to enable the proof-of-concept compiler plugin *through* your crate. You should also copy and modify the following section (replacing `whizzo` with your crate's name). 453 | 454 | ### For Crate Users 455 | 456 | Add the following to your `Cargo.toml` manifest: 457 | 458 | ```toml 459 | [features] 460 | use-parse-generics-poc = [ 461 | "whizzo/use-parse-generics-poc", 462 | "parse-generics-poc", 463 | "parse-generics-shim/use-parse-generics-poc", 464 | ] 465 | 466 | [dependencies] 467 | whizzo = "0.1.0" 468 | parse-generics-poc = { version = "0.1.0", optional = true } 469 | parse-generics-shim = "0.1.0" 470 | ``` 471 | 472 | Then, add the following to your crate's root module: 473 | 474 | ```ignore 475 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 476 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 477 | #[macro_use] extern crate parse_generics_shim; 478 | #[macro_use] extern crate whizzo; 479 | ``` 480 | 481 | By default, this will use stable-but-inferior implementations of the generics-parsing macros. In particular, you cannot use lifetimes other than `'a` through `'z`, and macros may fail to expand for sufficiently complex inputs. 482 | 483 | If a macro fails to expand due to the "recursion limit", place the following attribute at the top of your crate's root module, and raise the number until the macro works: 484 | 485 | ```rust 486 | #![recursion_limit="32"] 487 | ``` 488 | 489 | If you are using a compatible nightly compiler, you can enable the fully-featured versions of the generics-parsing macros (see the proposed [RFC #1583](https://github.com/rust-lang/rfcs/pull/1583) for context). If you have followed the instructions above, this can be done by adding `--features=use-parse-generic-poc` to your `cargo build` command. 490 | 491 | The [documentation for `parse-generics-poc`](https://danielkeep.github.io/rust-parse-generics/doc/parse_generics_poc/index.html) will specify *which* nightly it is known to be compatible with. If you are using `rustup`, you can configure your crate to use the appropriate compiler using the following (replacing the date shown with the one listed in the `parse-generics-poc` documentation): 492 | 493 | ```sh 494 | rustup override add nightly-2016-04-06 495 | ``` 496 | */ 497 | #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 498 | #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 499 | 500 | #[cfg(not(feature="use-parse-generics-poc"))] 501 | #[doc(hidden)] 502 | #[macro_export] 503 | macro_rules! parse_generics_shim_util { 504 | ( 505 | @callback 506 | ($cb_name:ident ! ($($cb_arg:tt)*)), 507 | $($tail:tt)* 508 | ) => { 509 | $cb_name! { $($cb_arg)* $($tail)* } 510 | }; 511 | 512 | ( 513 | @callback 514 | ($cb_name:ident ! [$($cb_arg:tt)*]), 515 | $($tail:tt)* 516 | ) => { 517 | $cb_name! { $($cb_arg)* $($tail)* } 518 | }; 519 | 520 | ( 521 | @callback 522 | ($cb_name:ident ! {$($cb_arg:tt)*}), 523 | $($tail:tt)* 524 | ) => { 525 | $cb_name! { $($cb_arg)* $($tail)* } 526 | }; 527 | } 528 | 529 | mod parse_constr; 530 | mod parse_generics_shim; 531 | mod parse_where_shim; 532 | -------------------------------------------------------------------------------- /parse-generics-shim/src/parse_constr.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[cfg(not(feature="use-parse-generics-poc"))] 11 | #[doc(hidden)] 12 | #[macro_export] 13 | macro_rules! parse_constr { 14 | ( 15 | @parse 16 | { $callback:tt }, $allow:tt, $constr:tt, 17 | , $($body:tt)* 18 | ) => { 19 | parse_generics_shim_util! { 20 | @callback 21 | $callback, 22 | $constr, 23 | , $($body)* 24 | } 25 | }; 26 | 27 | ( 28 | @parse 29 | { $callback:tt }, $allow:tt, $constr:tt, 30 | > $($body:tt)* 31 | ) => { 32 | parse_generics_shim_util! { 33 | @callback 34 | $callback, 35 | $constr, 36 | > $($body)* 37 | } 38 | }; 39 | 40 | ( 41 | @parse 42 | { $callback:tt }, $allow:tt, $constr:tt, 43 | ; $($body:tt)* 44 | ) => { 45 | parse_generics_shim_util! { 46 | @callback 47 | $callback, 48 | $constr, 49 | ; $($body)* 50 | } 51 | }; 52 | 53 | ( 54 | @parse 55 | { $callback:tt }, $allow:tt, $constr:tt, 56 | = $($body:tt)* 57 | ) => { 58 | parse_generics_shim_util! { 59 | @callback 60 | $callback, 61 | $constr, 62 | = $($body)* 63 | } 64 | }; 65 | 66 | ( 67 | @parse 68 | { $callback:tt }, $allow:tt, $constr:tt, 69 | {$($delim:tt)*} $($body:tt)* 70 | ) => { 71 | parse_generics_shim_util! { 72 | @callback 73 | $callback, 74 | $constr, 75 | {$($delim)*} $($body)* 76 | } 77 | }; 78 | 79 | ( 80 | @parse 81 | $prefix:tt, $allow:tt, {$($constr:tt)*}, 82 | + $($body:tt)* 83 | ) => { 84 | parse_constr! { 85 | @parse 86 | $prefix, $allow, 87 | {$($constr)* +}, 88 | $($body)* 89 | } 90 | }; 91 | 92 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'static $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'static}, $($body)* } }; 93 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'a $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'a}, $($body)* } }; 94 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'b $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'b}, $($body)* } }; 95 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'c $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'c}, $($body)* } }; 96 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'd $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'd}, $($body)* } }; 97 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'e $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'e}, $($body)* } }; 98 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'f $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'f}, $($body)* } }; 99 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'g $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'g}, $($body)* } }; 100 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'h $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'h}, $($body)* } }; 101 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'i $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'i}, $($body)* } }; 102 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'j $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'j}, $($body)* } }; 103 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'k $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'k}, $($body)* } }; 104 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'l $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'l}, $($body)* } }; 105 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'm $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'm}, $($body)* } }; 106 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'n $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'n}, $($body)* } }; 107 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'o $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'o}, $($body)* } }; 108 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'p $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'p}, $($body)* } }; 109 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'q $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'q}, $($body)* } }; 110 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'r $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'r}, $($body)* } }; 111 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 's $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 's}, $($body)* } }; 112 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 't $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 't}, $($body)* } }; 113 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'u $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'u}, $($body)* } }; 114 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'v $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'v}, $($body)* } }; 115 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'w $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'w}, $($body)* } }; 116 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'x $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'x}, $($body)* } }; 117 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'y $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'y}, $($body)* } }; 118 | (@parse $prefix:tt, (true, $atr:tt), {$($constr:tt)*}, 'z $($body:tt)*) => { parse_constr! { @parse $prefix, (true, $atr), {$($constr)* 'z}, $($body)* } }; 119 | 120 | ( 121 | @parse 122 | $prefix:tt, $allow:tt, {$($constr:tt)*}, 123 | ?Sized $($body:tt)* 124 | ) => { 125 | parse_constr! { 126 | @parse 127 | $prefix, $allow, 128 | {$($constr)* ?Sized}, 129 | $($body)* 130 | } 131 | }; 132 | 133 | ( 134 | @parse 135 | $prefix:tt, ($_alt:tt, true), {$($constr:tt)*}, 136 | :: $($body:tt)* 137 | ) => { 138 | parse_constr! { 139 | @parse 140 | $prefix, (false, true), 141 | {$($constr)* ::}, 142 | $($body)* 143 | } 144 | }; 145 | 146 | ( 147 | @parse 148 | $prefix:tt, ($_alt:tt, true), {$($constr:tt)*}, 149 | < $($body:tt)* 150 | ) => { 151 | parse_constr! { 152 | @parse_delim 153 | { $prefix, (false, true) }, 154 | [ # ], 155 | {$($constr)* <}, 156 | $($body)* 157 | } 158 | }; 159 | 160 | ( 161 | @parse 162 | $prefix:tt, ($_alt:tt, true), {$($constr:tt)*}, 163 | $trname:ident $($body:tt)* 164 | ) => { 165 | parse_constr! { 166 | @parse 167 | $prefix, (false, true), 168 | {$($constr)* $trname}, 169 | $($body)* 170 | } 171 | }; 172 | 173 | ( 174 | @parse_delim 175 | { $prefix:tt, $allow:tt }, 176 | [ # ], {$($constr:tt)*}, 177 | > $($body:tt)* 178 | ) => { 179 | parse_constr! { 180 | @parse 181 | $prefix, $allow, {$($constr)* >}, 182 | $($body)* 183 | } 184 | }; 185 | 186 | ( 187 | @parse_delim 188 | { $prefix:tt, $allow:tt }, 189 | [ # ], {$($constr:tt)*}, 190 | >> $($body:tt)* 191 | ) => { 192 | parse_constr! { 193 | @parse 194 | $prefix, $allow, {$($constr)* >}, 195 | > $($body)* 196 | } 197 | }; 198 | 199 | ( 200 | @parse_delim 201 | { $prefix:tt, $allow:tt }, 202 | [ # # ], {$($constr:tt)*}, 203 | >> $($body:tt)* 204 | ) => { 205 | parse_constr! { 206 | @parse 207 | $prefix, $allow, {$($constr)* >>}, 208 | $($body)* 209 | } 210 | }; 211 | 212 | ( 213 | @parse_delim 214 | $prefix:tt, 215 | [ $($stack:tt)* ], {$($constr:tt)*}, 216 | < $($body:tt)* 217 | ) => { 218 | parse_constr! { 219 | @parse_delim 220 | $prefix, [ # $($stack)* ], {$($constr)* <}, 221 | $($body)* 222 | } 223 | }; 224 | 225 | ( 226 | @parse_delim 227 | $prefix:tt, 228 | [ # $($stack:tt)* ], {$($constr:tt)*}, 229 | > $($body:tt)* 230 | ) => { 231 | parse_constr! { 232 | @parse_delim 233 | $prefix, [ $($stack)* ], {$($constr)* >}, 234 | $($body)* 235 | } 236 | }; 237 | 238 | ( 239 | @parse_delim 240 | $prefix:tt, 241 | [ # # $($stack:tt)* ], {$($constr:tt)*}, 242 | >> $($body:tt)* 243 | ) => { 244 | parse_constr! { 245 | @parse_delim 246 | $prefix, [ $($stack)* ], {$($constr)* >>}, 247 | $($body)* 248 | } 249 | }; 250 | 251 | ( 252 | @parse_delim 253 | $prefix:tt, 254 | $stack:tt, {$($constr:tt)*}, 255 | $other:tt $($body:tt)* 256 | ) => { 257 | parse_constr! { 258 | @parse_delim 259 | $prefix, $stack, {$($constr)* $other}, 260 | $($body)* 261 | } 262 | }; 263 | 264 | ( 265 | ($allow_lt:tt, $allow_tr:tt), 266 | then $callback:ident!$callback_arg:tt, 267 | $($body:tt)* 268 | ) => { 269 | parse_constr! { 270 | @parse 271 | { 272 | ($callback!$callback_arg) 273 | }, 274 | ($allow_lt, $allow_tr), 275 | {}, 276 | $($body)* 277 | } 278 | }; 279 | } 280 | -------------------------------------------------------------------------------- /parse-generics-shim/src/parse_generics_shim.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[cfg(feature="use-parse-generics-poc")] 11 | #[doc(hidden)] 12 | #[macro_export] 13 | macro_rules! parse_generics_shim { 14 | ($($body:tt)*) => { 15 | parse_generics! { $($body)* } 16 | }; 17 | } 18 | 19 | #[cfg(not(feature="use-parse-generics-poc"))] 20 | #[doc(hidden)] 21 | #[macro_export] 22 | macro_rules! parse_generics_shim { 23 | ( 24 | @parse_start 25 | $prefix:tt, 26 | <> $($tail:tt)* 27 | ) => { 28 | parse_generics_shim! { 29 | @emit_output 30 | $prefix, 31 | { 32 | constr: [], 33 | ltimes: [], 34 | tnames: [], 35 | }, 36 | $($tail)* 37 | } 38 | }; 39 | 40 | ( 41 | @parse_start 42 | $prefix:tt, 43 | < $($tail:tt)* 44 | ) => { 45 | parse_generics_shim! { 46 | @parse 47 | $prefix, 48 | { 49 | constr: [], 50 | ltimes: [], 51 | tnames: [], 52 | }, 53 | $($tail)* 54 | } 55 | }; 56 | 57 | ( 58 | @parse_start 59 | $prefix:tt, 60 | $($tail:tt)* 61 | ) => { 62 | parse_generics_shim! { 63 | @emit_output 64 | $prefix, 65 | { 66 | constr: [], 67 | ltimes: [], 68 | tnames: [], 69 | }, 70 | $($tail)* 71 | } 72 | }; 73 | 74 | ( 75 | @parse 76 | $prefix:tt, 77 | $fields:tt, 78 | > $($tail:tt)* 79 | ) => { 80 | parse_generics_shim! { 81 | @emit_output 82 | $prefix, 83 | $fields, 84 | $($tail)* 85 | } 86 | }; 87 | 88 | ( 89 | @parse 90 | $prefix:tt, 91 | $fields:tt, 92 | $(,)+ $($tail:tt)* 93 | ) => { 94 | parse_generics_shim! { 95 | @parse 96 | $prefix, 97 | $fields, 98 | $($tail)* 99 | } 100 | }; 101 | 102 | (@parse $prefix:tt, $fields:tt, 'static: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'static: }, $($tail)* } }; 103 | (@parse $prefix:tt, $fields:tt, 'a: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'a: }, $($tail)* } }; 104 | (@parse $prefix:tt, $fields:tt, 'b: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'b: }, $($tail)* } }; 105 | (@parse $prefix:tt, $fields:tt, 'c: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'c: }, $($tail)* } }; 106 | (@parse $prefix:tt, $fields:tt, 'd: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'd: }, $($tail)* } }; 107 | (@parse $prefix:tt, $fields:tt, 'e: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'e: }, $($tail)* } }; 108 | (@parse $prefix:tt, $fields:tt, 'f: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'f: }, $($tail)* } }; 109 | (@parse $prefix:tt, $fields:tt, 'g: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'g: }, $($tail)* } }; 110 | (@parse $prefix:tt, $fields:tt, 'h: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'h: }, $($tail)* } }; 111 | (@parse $prefix:tt, $fields:tt, 'i: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'i: }, $($tail)* } }; 112 | (@parse $prefix:tt, $fields:tt, 'j: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'j: }, $($tail)* } }; 113 | (@parse $prefix:tt, $fields:tt, 'k: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'k: }, $($tail)* } }; 114 | (@parse $prefix:tt, $fields:tt, 'l: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'l: }, $($tail)* } }; 115 | (@parse $prefix:tt, $fields:tt, 'm: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'm: }, $($tail)* } }; 116 | (@parse $prefix:tt, $fields:tt, 'n: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'n: }, $($tail)* } }; 117 | (@parse $prefix:tt, $fields:tt, 'o: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'o: }, $($tail)* } }; 118 | (@parse $prefix:tt, $fields:tt, 'p: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'p: }, $($tail)* } }; 119 | (@parse $prefix:tt, $fields:tt, 'q: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'q: }, $($tail)* } }; 120 | (@parse $prefix:tt, $fields:tt, 'r: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'r: }, $($tail)* } }; 121 | (@parse $prefix:tt, $fields:tt, 's: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 's: }, $($tail)* } }; 122 | (@parse $prefix:tt, $fields:tt, 't: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 't: }, $($tail)* } }; 123 | (@parse $prefix:tt, $fields:tt, 'u: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'u: }, $($tail)* } }; 124 | (@parse $prefix:tt, $fields:tt, 'v: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'v: }, $($tail)* } }; 125 | (@parse $prefix:tt, $fields:tt, 'w: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'w: }, $($tail)* } }; 126 | (@parse $prefix:tt, $fields:tt, 'x: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'x: }, $($tail)* } }; 127 | (@parse $prefix:tt, $fields:tt, 'y: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'y: }, $($tail)* } }; 128 | (@parse $prefix:tt, $fields:tt, 'z: $($tail:tt)*) => { parse_constr! { (true, false), then parse_generics_shim! { @app_lt $prefix, $fields, 'z: }, $($tail)* } }; 129 | 130 | (@parse $prefix:tt, $fields:tt, 'static $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'static: {}, $($tail)* } }; 131 | (@parse $prefix:tt, $fields:tt, 'a $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'a: {}, $($tail)* } }; 132 | (@parse $prefix:tt, $fields:tt, 'b $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'b: {}, $($tail)* } }; 133 | (@parse $prefix:tt, $fields:tt, 'c $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'c: {}, $($tail)* } }; 134 | (@parse $prefix:tt, $fields:tt, 'd $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'd: {}, $($tail)* } }; 135 | (@parse $prefix:tt, $fields:tt, 'e $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'e: {}, $($tail)* } }; 136 | (@parse $prefix:tt, $fields:tt, 'f $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'f: {}, $($tail)* } }; 137 | (@parse $prefix:tt, $fields:tt, 'g $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'g: {}, $($tail)* } }; 138 | (@parse $prefix:tt, $fields:tt, 'h $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'h: {}, $($tail)* } }; 139 | (@parse $prefix:tt, $fields:tt, 'i $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'i: {}, $($tail)* } }; 140 | (@parse $prefix:tt, $fields:tt, 'j $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'j: {}, $($tail)* } }; 141 | (@parse $prefix:tt, $fields:tt, 'k $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'k: {}, $($tail)* } }; 142 | (@parse $prefix:tt, $fields:tt, 'l $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'l: {}, $($tail)* } }; 143 | (@parse $prefix:tt, $fields:tt, 'm $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'm: {}, $($tail)* } }; 144 | (@parse $prefix:tt, $fields:tt, 'n $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'n: {}, $($tail)* } }; 145 | (@parse $prefix:tt, $fields:tt, 'o $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'o: {}, $($tail)* } }; 146 | (@parse $prefix:tt, $fields:tt, 'p $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'p: {}, $($tail)* } }; 147 | (@parse $prefix:tt, $fields:tt, 'q $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'q: {}, $($tail)* } }; 148 | (@parse $prefix:tt, $fields:tt, 'r $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'r: {}, $($tail)* } }; 149 | (@parse $prefix:tt, $fields:tt, 's $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 's: {}, $($tail)* } }; 150 | (@parse $prefix:tt, $fields:tt, 't $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 't: {}, $($tail)* } }; 151 | (@parse $prefix:tt, $fields:tt, 'u $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'u: {}, $($tail)* } }; 152 | (@parse $prefix:tt, $fields:tt, 'v $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'v: {}, $($tail)* } }; 153 | (@parse $prefix:tt, $fields:tt, 'w $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'w: {}, $($tail)* } }; 154 | (@parse $prefix:tt, $fields:tt, 'x $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'x: {}, $($tail)* } }; 155 | (@parse $prefix:tt, $fields:tt, 'y $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'y: {}, $($tail)* } }; 156 | (@parse $prefix:tt, $fields:tt, 'z $($tail:tt)* ) => { parse_generics_shim! { @app_lt $prefix, $fields, 'z: {}, $($tail)* } }; 157 | 158 | ( 159 | @app_lt 160 | $prefix:tt, 161 | { 162 | constr: [$($constr:tt)*], 163 | ltimes: [$($ltimes:tt)*], 164 | tnames: $tnames:tt, 165 | }, 166 | $lt:tt: {}, 167 | $($tail:tt)* 168 | ) => { 169 | parse_generics_shim! { 170 | @parse 171 | $prefix, 172 | { 173 | constr: [$($constr)* $lt,], 174 | ltimes: [$($ltimes)* $lt,], 175 | tnames: $tnames, 176 | }, 177 | $($tail)* 178 | } 179 | }; 180 | 181 | ( 182 | @app_lt 183 | $prefix:tt, 184 | { 185 | constr: [$($constr:tt)*], 186 | ltimes: [$($ltimes:tt)*], 187 | tnames: $tnames:tt, 188 | }, 189 | $lt:tt: {$($ltconstr:tt)*}, 190 | $($tail:tt)* 191 | ) => { 192 | parse_generics_shim! { 193 | @parse 194 | $prefix, 195 | { 196 | constr: [$($constr)* $lt: $($ltconstr)*,], 197 | ltimes: [$($ltimes)* $lt,], 198 | tnames: $tnames, 199 | }, 200 | $($tail)* 201 | } 202 | }; 203 | 204 | ( 205 | @parse 206 | $prefix:tt, 207 | $fields:tt, 208 | $tname:ident: $($tail:tt)* 209 | ) => { 210 | parse_constr! { 211 | (true, true), 212 | then parse_generics_shim! { 213 | @app_ty 214 | $prefix, 215 | $fields, 216 | $tname: 217 | }, 218 | $($tail)* 219 | } 220 | }; 221 | 222 | ( 223 | @parse 224 | $prefix:tt, 225 | { 226 | constr: [$($constr:tt)*], 227 | ltimes: $ltimes:tt, 228 | tnames: [$($tnames:tt)*], 229 | }, 230 | $tname:ident $($tail:tt)* 231 | ) => { 232 | parse_generics_shim! { 233 | @parse 234 | $prefix, 235 | { 236 | constr: [$($constr)* $tname,], 237 | ltimes: $ltimes, 238 | tnames: [$($tnames)* $tname,], 239 | }, 240 | $($tail)* 241 | } 242 | }; 243 | 244 | ( 245 | @app_ty 246 | $prefix:tt, 247 | { 248 | constr: [$($constr:tt)*], 249 | ltimes: $ltimes:tt, 250 | tnames: [$($tnames:tt)*], 251 | }, 252 | $ty:ident: {}, 253 | $($tail:tt)* 254 | ) => { 255 | parse_generics_shim! { 256 | @parse 257 | $prefix, 258 | { 259 | constr: [$($constr)* $ty,], 260 | ltimes: $ltimes, 261 | tnames: [$($tnames)* $ty,], 262 | }, 263 | $($tail)* 264 | } 265 | }; 266 | 267 | ( 268 | @app_ty 269 | $prefix:tt, 270 | { 271 | constr: [$($constr:tt)*], 272 | ltimes: $ltimes:tt, 273 | tnames: [$($tnames:tt)*], 274 | }, 275 | $ty:ident: {$($tyconstr:tt)*}, 276 | $($tail:tt)* 277 | ) => { 278 | parse_generics_shim! { 279 | @parse 280 | $prefix, 281 | { 282 | constr: [$($constr)* $ty: $($tyconstr)*,], 283 | ltimes: $ltimes, 284 | tnames: [$($tnames)* $ty,], 285 | }, 286 | $($tail)* 287 | } 288 | }; 289 | 290 | ( 291 | @emit_output 292 | { { .. }, $callback:tt }, 293 | { 294 | constr: $constr:tt, 295 | ltimes: [$($ltimes:tt)*], 296 | tnames: [$($tnames:tt)*], 297 | }, 298 | $($tail:tt)* 299 | ) => { 300 | parse_generics_shim_util! { 301 | @callback 302 | $callback, 303 | { 304 | constr: $constr, 305 | params: [$($ltimes)* $($tnames)*], 306 | ltimes: [$($ltimes)*], 307 | tnames: [$($tnames)*], 308 | .. 309 | }, 310 | $($tail)* 311 | } 312 | }; 313 | 314 | ( 315 | @emit_output 316 | { { constr, params, ltimes, tnames }, $callback:tt }, 317 | { 318 | constr: $constr:tt, 319 | ltimes: [$($ltimes:tt)*], 320 | tnames: [$($tnames:tt)*], 321 | }, 322 | $($tail:tt)* 323 | ) => { 324 | parse_generics_shim_util! { 325 | @callback 326 | $callback, 327 | { 328 | constr: $constr, 329 | params: [$($ltimes)* $($tnames)*], 330 | ltimes: [$($ltimes)*], 331 | tnames: [$($tnames)*], 332 | }, 333 | $($tail)* 334 | } 335 | }; 336 | 337 | ( 338 | @emit_output 339 | { { constr }, $callback:tt }, 340 | { 341 | constr: $constr:tt, 342 | ltimes: [$($ltimes:tt)*], 343 | tnames: [$($tnames:tt)*], 344 | }, 345 | $($tail:tt)* 346 | ) => { 347 | parse_generics_shim_util! { 348 | @callback 349 | $callback, 350 | { 351 | constr: $constr, 352 | }, 353 | $($tail)* 354 | } 355 | }; 356 | 357 | ( 358 | $fields:tt, 359 | then $callback:ident!$callback_arg:tt, 360 | $($body:tt)* 361 | ) => { 362 | parse_generics_shim! { 363 | @parse_start 364 | { $fields, ($callback!$callback_arg) }, 365 | $($body)* 366 | } 367 | }; 368 | } 369 | -------------------------------------------------------------------------------- /parse-generics-shim/src/parse_where_shim.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[cfg(feature="use-parse-generics-poc")] 11 | #[doc(hidden)] 12 | #[macro_export] 13 | macro_rules! parse_where_shim { 14 | ($($body:tt)*) => { 15 | parse_where! { $($body)* } 16 | }; 17 | } 18 | 19 | #[cfg(not(feature="use-parse-generics-poc"))] 20 | #[doc(hidden)] 21 | #[macro_export] 22 | macro_rules! parse_where_shim { 23 | ( 24 | @parse 25 | $prefix:tt, $fields:tt, 26 | ; $($tail:tt)* 27 | ) => { 28 | parse_where_shim! { 29 | @emit_output 30 | $prefix, $fields, 31 | ; $($tail)* 32 | } 33 | }; 34 | 35 | ( 36 | @parse 37 | $prefix:tt, $fields:tt, 38 | = $($tail:tt)* 39 | ) => { 40 | parse_where_shim! { 41 | @emit_output 42 | $prefix, $fields, 43 | = $($tail)* 44 | } 45 | }; 46 | 47 | ( 48 | @parse 49 | $prefix:tt, $fields:tt, 50 | {$($delim:tt)*} $($tail:tt)* 51 | ) => { 52 | parse_where_shim! { 53 | @emit_output 54 | $prefix, $fields, 55 | {$($delim)*} $($tail)* 56 | } 57 | }; 58 | 59 | ( 60 | @parse 61 | $prefix:tt, $fields:tt, 62 | $(,)+ $($tail:tt)* 63 | ) => { 64 | parse_where_shim! { 65 | @parse 66 | $prefix, $fields, 67 | $($tail)* 68 | } 69 | }; 70 | 71 | (@parse $prefix:tt, $fields:tt, 'static: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'static}: }, $($tail)* } }; 72 | (@parse $prefix:tt, $fields:tt, 'a: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'a}: }, $($tail)* } }; 73 | (@parse $prefix:tt, $fields:tt, 'b: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'b}: }, $($tail)* } }; 74 | (@parse $prefix:tt, $fields:tt, 'c: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'c}: }, $($tail)* } }; 75 | (@parse $prefix:tt, $fields:tt, 'd: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'d}: }, $($tail)* } }; 76 | (@parse $prefix:tt, $fields:tt, 'e: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'e}: }, $($tail)* } }; 77 | (@parse $prefix:tt, $fields:tt, 'f: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'f}: }, $($tail)* } }; 78 | (@parse $prefix:tt, $fields:tt, 'g: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'g}: }, $($tail)* } }; 79 | (@parse $prefix:tt, $fields:tt, 'h: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'h}: }, $($tail)* } }; 80 | (@parse $prefix:tt, $fields:tt, 'i: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'i}: }, $($tail)* } }; 81 | (@parse $prefix:tt, $fields:tt, 'j: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'j}: }, $($tail)* } }; 82 | (@parse $prefix:tt, $fields:tt, 'k: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'k}: }, $($tail)* } }; 83 | (@parse $prefix:tt, $fields:tt, 'l: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'l}: }, $($tail)* } }; 84 | (@parse $prefix:tt, $fields:tt, 'm: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'m}: }, $($tail)* } }; 85 | (@parse $prefix:tt, $fields:tt, 'n: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'n}: }, $($tail)* } }; 86 | (@parse $prefix:tt, $fields:tt, 'o: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'o}: }, $($tail)* } }; 87 | (@parse $prefix:tt, $fields:tt, 'p: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'p}: }, $($tail)* } }; 88 | (@parse $prefix:tt, $fields:tt, 'q: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'q}: }, $($tail)* } }; 89 | (@parse $prefix:tt, $fields:tt, 'r: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'r}: }, $($tail)* } }; 90 | (@parse $prefix:tt, $fields:tt, 's: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'s}: }, $($tail)* } }; 91 | (@parse $prefix:tt, $fields:tt, 't: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'t}: }, $($tail)* } }; 92 | (@parse $prefix:tt, $fields:tt, 'u: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'u}: }, $($tail)* } }; 93 | (@parse $prefix:tt, $fields:tt, 'v: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'v}: }, $($tail)* } }; 94 | (@parse $prefix:tt, $fields:tt, 'w: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'w}: }, $($tail)* } }; 95 | (@parse $prefix:tt, $fields:tt, 'x: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'x}: }, $($tail)* } }; 96 | (@parse $prefix:tt, $fields:tt, 'y: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'y}: }, $($tail)* } }; 97 | (@parse $prefix:tt, $fields:tt, 'z: $($tail:tt)*) => { parse_constr! { (true, false), then parse_where_shim! { @app_con $prefix, $fields, {'z}: }, $($tail)* } }; 98 | 99 | ( 100 | @parse 101 | $prefix:tt, 102 | $fields:tt, 103 | for $($tail:tt)* 104 | ) => { 105 | parse_generics_shim! { 106 | { constr }, 107 | then parse_where_shim! { @parsed_for $prefix, $fields, }, 108 | $($tail)* 109 | } 110 | }; 111 | 112 | ( 113 | @parse 114 | $prefix:tt, 115 | $fields:tt, 116 | $tname:ident: $($tail:tt)* 117 | ) => { 118 | parse_constr! { 119 | (true, true), 120 | then parse_where_shim! { @app_con $prefix, $fields, {$tname}: }, 121 | $($tail)* 122 | } 123 | }; 124 | 125 | ( 126 | @app_con 127 | $prefix:tt, 128 | { preds: [$($preds:tt)*], }, 129 | {$($thing:tt)*}: {}, 130 | $($body:tt)* 131 | ) => { 132 | parse_where_shim! { 133 | @parse 134 | $prefix, 135 | { preds: [$($preds)* $($thing)*,], }, 136 | $($body)* 137 | } 138 | }; 139 | 140 | ( 141 | @app_con 142 | $prefix:tt, 143 | { preds: [$($preds:tt)*], }, 144 | {$($thing:tt)*}: {$($constr:tt)*}, 145 | $($body:tt)* 146 | ) => { 147 | parse_where_shim! { 148 | @parse 149 | $prefix, 150 | { preds: [$($preds)* $($thing)*: $($constr)*,], }, 151 | $($body)* 152 | } 153 | }; 154 | 155 | ( 156 | @parsed_for 157 | $prefix:tt, 158 | $fields:tt, 159 | { constr: [], }, 160 | $tname:ident: $($tail:tt)* 161 | ) => { 162 | parse_constr! { 163 | (true, true), 164 | then parse_where_shim! { @app_con $prefix, $fields, {$tname}: }, 165 | $($tail)* 166 | } 167 | }; 168 | 169 | ( 170 | @parsed_for 171 | $prefix:tt, 172 | $fields:tt, 173 | { constr: [$($constr:tt)*], }, 174 | $tname:ident: $($tail:tt)* 175 | ) => { 176 | parse_constr! { 177 | (true, true), 178 | then parse_where_shim! { @app_con $prefix, $fields, {for<$($constr)*> $tname}: }, 179 | $($tail)* 180 | } 181 | }; 182 | 183 | ( 184 | @emit_output 185 | { { .. }, $callback:tt }, 186 | { 187 | preds: [], 188 | }, 189 | $($tail:tt)* 190 | ) => { 191 | parse_generics_shim_util! { 192 | @callback 193 | $callback, 194 | { 195 | clause: [], 196 | preds: [], 197 | .. 198 | }, 199 | $($tail)* 200 | } 201 | }; 202 | 203 | ( 204 | @emit_output 205 | { { .. }, $callback:tt }, 206 | { 207 | preds: [$($preds:tt)*], 208 | }, 209 | $($tail:tt)* 210 | ) => { 211 | parse_generics_shim_util! { 212 | @callback 213 | $callback, 214 | { 215 | clause: [where $($preds)*], 216 | preds: [$($preds)*], 217 | .. 218 | }, 219 | $($tail)* 220 | } 221 | }; 222 | 223 | ( 224 | @emit_output 225 | { { clause, preds }, $callback:tt }, 226 | { 227 | preds: [], 228 | }, 229 | $($tail:tt)* 230 | ) => { 231 | parse_generics_shim_util! { 232 | @callback 233 | $callback, 234 | { 235 | clause: [], 236 | preds: [], 237 | }, 238 | $($tail)* 239 | } 240 | }; 241 | 242 | ( 243 | @emit_output 244 | { { clause, preds }, $callback:tt }, 245 | { 246 | preds: [$($preds:tt)*], 247 | }, 248 | $($tail:tt)* 249 | ) => { 250 | parse_generics_shim_util! { 251 | @callback 252 | $callback, 253 | { 254 | clause: [where $($preds)*], 255 | preds: [$($preds)*], 256 | }, 257 | $($tail)* 258 | } 259 | }; 260 | 261 | ( 262 | @emit_output 263 | { { preds }, $callback:tt }, 264 | $fields:tt, 265 | $($tail:tt)* 266 | ) => { 267 | parse_generics_shim_util! { 268 | @callback 269 | $callback, 270 | $fields, 271 | $($tail)* 272 | } 273 | }; 274 | 275 | ( 276 | $fields:tt, 277 | then $callback:ident!$callback_arg:tt, 278 | where $($body:tt)* 279 | ) => { 280 | parse_where_shim! { 281 | @parse 282 | { $fields, ($callback!$callback_arg) }, 283 | { preds: [], }, 284 | $($body)* 285 | } 286 | }; 287 | 288 | ( 289 | $fields:tt, 290 | then $callback:ident!$callback_arg:tt, 291 | $($body:tt)* 292 | ) => { 293 | parse_where_shim! { 294 | @emit_output 295 | { $fields, ($callback!$callback_arg) }, 296 | { preds: [], }, 297 | $($body)* 298 | } 299 | }; 300 | } 301 | -------------------------------------------------------------------------------- /parse-generics-shim/tests/parse_constr.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg(not(feature="use-parse-generics-poc"))] 11 | #[macro_use] extern crate parse_generics_shim; 12 | extern crate rustc_version; 13 | 14 | macro_rules! aeqiws { 15 | ($lhs:expr, $rhs:expr) => { 16 | { 17 | let lhs = $lhs; 18 | let rhs = $rhs; 19 | let lhs_words = $lhs.split_whitespace(); 20 | let rhs_words = $rhs.split_whitespace(); 21 | for (i, (l, r)) in lhs_words.zip(rhs_words).enumerate() { 22 | if l != r { 23 | panic!("assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`, at word {}, `{:?}` != `{:?}`)", lhs, rhs, i, l, r); 24 | } 25 | } 26 | } 27 | }; 28 | } 29 | 30 | macro_rules! pgts { 31 | ($($body:tt)*) => { 32 | parse_constr! { 33 | (true, true), 34 | then stringify!(), 35 | $($body)* 36 | } 37 | }; 38 | } 39 | 40 | macro_rules! rv { 41 | ($($tts:tt)*) => { 42 | ::rustc_version::version_matches(concat!($(stringify!($tts)),*)) 43 | }; 44 | } 45 | 46 | #[test] 47 | fn test_simple() { 48 | aeqiws!(pgts!('a, X), "{ 'a } , , X"); 49 | aeqiws!(pgts!('a> X), "{ 'a } , > X"); 50 | aeqiws!(pgts!('a {X}), "{ 'a } , { X }"); 51 | aeqiws!(pgts!('a; X), "{ 'a } , ; X"); 52 | aeqiws!(pgts!('a = X), "{ 'a } , = X"); 53 | 54 | aeqiws!(pgts!(T; X), "{ T } , ; X"); 55 | aeqiws!(pgts!('a + T; X), "{ 'a + T } , ; X"); 56 | aeqiws!(pgts!('a + 'b; X), "{ 'a + 'b } , ; X"); 57 | aeqiws!(pgts!('a + 'b + T; X), "{ 'a + 'b + T } , ; X"); 58 | aeqiws!(pgts!('a + ::std::clone::Clone; X), 59 | if rv!(1.10) { "{ 'a + :: std :: clone :: Clone } , ; X" } 60 | else { "{ 'a + :: std:: clone:: Clone } , ; X" } ); 61 | aeqiws!(pgts!('a + From; X), "{ 'a + From < u8 > } , ; X"); 62 | aeqiws!(pgts!('a + From>; X), "{ 'a + From < Bar < u8 >> } , ; X"); 63 | aeqiws!(pgts!('a + From> X), "{ 'a + From < Bar > } , > X"); 64 | } 65 | -------------------------------------------------------------------------------- /parse-generics-shim/tests/parse_generics.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 11 | #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 12 | #[macro_use] extern crate parse_generics_shim; 13 | 14 | macro_rules! as_item { ($i:item) => { $i } } 15 | 16 | macro_rules! aeqiws { 17 | ($lhs:expr, $rhs:expr) => { 18 | { 19 | let lhs = $lhs; 20 | let rhs = $rhs; 21 | let lhs_words = $lhs.split_whitespace(); 22 | let rhs_words = $rhs.split_whitespace(); 23 | for (i, (l, r)) in lhs_words.zip(rhs_words).enumerate() { 24 | if l != r { 25 | panic!("assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`, at word {}, `{:?}` != `{:?}`)", lhs, rhs, i, l, r); 26 | } 27 | } 28 | } 29 | }; 30 | } 31 | 32 | macro_rules! pgts { 33 | ($fields:tt, $($body:tt)*) => { 34 | parse_generics_shim! { 35 | $fields, 36 | then stringify!(), 37 | $($body)* 38 | } 39 | }; 40 | } 41 | 42 | #[test] 43 | fn test_no_generics() { 44 | aeqiws!( 45 | pgts!({..}, X), 46 | r#" 47 | { 48 | constr : [ ] , 49 | params : [ ] , 50 | ltimes : [ ] , 51 | tnames : [ ] , 52 | .. 53 | } , 54 | X 55 | "# 56 | ); 57 | 58 | aeqiws!( 59 | pgts!({..}, <> X), 60 | r#" 61 | { 62 | constr : [ ] , 63 | params : [ ] , 64 | ltimes : [ ] , 65 | tnames : [ ] , 66 | .. 67 | } , 68 | X 69 | "# 70 | ); 71 | 72 | aeqiws!( 73 | pgts!({ constr, params, ltimes, tnames }, X), 74 | r#" 75 | { 76 | constr : [ ] , 77 | params : [ ] , 78 | ltimes : [ ] , 79 | tnames : [ ] , 80 | } , 81 | X 82 | "# 83 | ); 84 | 85 | aeqiws!( 86 | pgts!({ constr, params, ltimes, tnames }, <> X), 87 | r#" 88 | { 89 | constr : [ ] , 90 | params : [ ] , 91 | ltimes : [ ] , 92 | tnames : [ ] , 93 | } , 94 | X 95 | "# 96 | ); 97 | } 98 | 99 | #[test] 100 | fn test_simple_ty_params() { 101 | aeqiws!( 102 | pgts!({ .. }, X), 103 | r#" 104 | { 105 | constr : [ T , ] , 106 | params : [ T , ] , 107 | ltimes : [ ] , 108 | tnames : [ T , ] , 109 | .. 110 | } , 111 | X 112 | "# 113 | ); 114 | 115 | aeqiws!( 116 | pgts!({ .. }, X), 117 | r#" 118 | { 119 | constr : [ T , U , ] , 120 | params : [ T , U , ] , 121 | ltimes : [ ] , 122 | tnames : [ T , U , ] , 123 | .. 124 | } , 125 | X 126 | "# 127 | ); 128 | 129 | aeqiws!( 130 | pgts!({ .. }, X), 131 | r#" 132 | { 133 | constr : [ T , U , ] , 134 | params : [ T , U , ] , 135 | ltimes : [ ] , 136 | tnames : [ T , U , ] , 137 | .. 138 | } , 139 | X 140 | "# 141 | ); 142 | } 143 | 144 | #[test] 145 | fn test_constr_ty_params() { 146 | aeqiws!( 147 | pgts!({ .. }, X), 148 | r#" 149 | { 150 | constr : [ T : Copy , ] , 151 | params : [ T , ] , 152 | ltimes : [ ] , 153 | tnames : [ T , ] , 154 | .. 155 | } , 156 | X 157 | "# 158 | ); 159 | 160 | aeqiws!( 161 | pgts!({ .. }, X), 162 | r#" 163 | { 164 | constr : [ T : Copy , ] , 165 | params : [ T , ] , 166 | ltimes : [ ] , 167 | tnames : [ T , ] , 168 | .. 169 | } , 170 | X 171 | "# 172 | ); 173 | 174 | aeqiws!( 175 | pgts!({ .. }, X), 176 | r#" 177 | { 178 | constr : [ T : Copy , U : Clone , ] , 179 | params : [ T , U , ] , 180 | ltimes : [ ] , 181 | tnames : [ T , U , ] , 182 | .. 183 | } , 184 | X 185 | "# 186 | ); 187 | 188 | aeqiws!( 189 | pgts!({ .. }, X), 190 | r#" 191 | { 192 | constr : [ T : Copy , U , V : Clone , ] , 193 | params : [ T , U , V , ] , 194 | ltimes : [ ] , 195 | tnames : [ T , U , V , ] , 196 | .. 197 | } , 198 | X 199 | "# 200 | ); 201 | 202 | aeqiws!( 203 | pgts!({ .. }, X), 204 | r#" 205 | { 206 | constr : [ T : 'a , U : 'a + Copy , ] , 207 | params : [ T , U , ] , 208 | ltimes : [ ] , 209 | tnames : [ T , U , ] , 210 | .. 211 | } , 212 | X 213 | "# 214 | ); 215 | 216 | aeqiws!( 217 | pgts!({ .. }, X), 218 | r#" 219 | { 220 | constr : [ T : ? Sized , ] , 221 | params : [ T , ] , 222 | ltimes : [ ] , 223 | tnames : [ T , ] , 224 | .. 225 | } , 226 | X 227 | "# 228 | ); 229 | 230 | aeqiws!( 231 | pgts!({ .. }, X), 232 | r#" 233 | { 234 | constr : [ T : ? Sized + 'a + Copy , ] , 235 | params : [ T , ] , 236 | ltimes : [ ] , 237 | tnames : [ T , ] , 238 | .. 239 | } , 240 | X 241 | "# 242 | ); 243 | 244 | aeqiws!( 245 | pgts!({ .. }, X), 246 | r#" 247 | { 248 | constr : [ T : 'a + ? Sized + Copy , ] , 249 | params : [ T , ] , 250 | ltimes : [ ] , 251 | tnames : [ T , ] , 252 | .. 253 | } , 254 | X 255 | "# 256 | ); 257 | 258 | aeqiws!( 259 | pgts!({ .. }, X), 260 | r#" 261 | { 262 | constr : [ T : 'a + Copy + ? Sized , ] , 263 | params : [ T , ] , 264 | ltimes : [ ] , 265 | tnames : [ T , ] , 266 | .. 267 | } , 268 | X 269 | "# 270 | ); 271 | } 272 | 273 | #[test] 274 | fn test_simple_lt_params() { 275 | aeqiws!( 276 | pgts!({ .. }, <'a> X), 277 | r#" 278 | { 279 | constr : [ 'a , ] , 280 | params : [ 'a , ] , 281 | ltimes : [ 'a , ] , 282 | tnames : [ ] , 283 | .. 284 | } , 285 | X 286 | "# 287 | ); 288 | 289 | aeqiws!( 290 | pgts!({ .. }, <'a,> X), 291 | r#" 292 | { 293 | constr : [ 'a , ] , 294 | params : [ 'a , ] , 295 | ltimes : [ 'a , ] , 296 | tnames : [ ] , 297 | .. 298 | } , 299 | X 300 | "# 301 | ); 302 | 303 | aeqiws!( 304 | pgts!({ .. }, <'a, 'b> X), 305 | r#" 306 | { 307 | constr : [ 'a , 'b , ] , 308 | params : [ 'a , 'b , ] , 309 | ltimes : [ 'a , 'b , ] , 310 | tnames : [ ] , 311 | .. 312 | } , 313 | X 314 | "# 315 | ); 316 | 317 | aeqiws!( 318 | pgts!({ .. }, <'a, 'b, 'i, 'z,> X), 319 | r#" 320 | { 321 | constr : [ 'a , 'b , 'i , 'z , ] , 322 | params : [ 'a , 'b , 'i , 'z , ] , 323 | ltimes : [ 'a , 'b , 'i , 'z , ] , 324 | tnames : [ ] , 325 | .. 326 | } , 327 | X 328 | "# 329 | ); 330 | } 331 | 332 | #[test] 333 | fn test_constr_lt_params() { 334 | aeqiws!( 335 | pgts!({ .. }, <'a: 'b> X), 336 | r#" 337 | { 338 | constr : [ 'a : 'b , ] , 339 | params : [ 'a , ] , 340 | ltimes : [ 'a , ] , 341 | tnames : [ ] , 342 | .. 343 | } , 344 | X 345 | "# 346 | ); 347 | 348 | aeqiws!( 349 | pgts!({ .. }, <'a: 'b + 'c> X), 350 | r#" 351 | { 352 | constr : [ 'a : 'b + 'c , ] , 353 | params : [ 'a , ] , 354 | ltimes : [ 'a , ] , 355 | tnames : [ ] , 356 | .. 357 | } , 358 | X 359 | "# 360 | ); 361 | 362 | aeqiws!( 363 | pgts!({ .. }, <'a: 'b + 'c,> X), 364 | r#" 365 | { 366 | constr : [ 'a : 'b + 'c , ] , 367 | params : [ 'a , ] , 368 | ltimes : [ 'a , ] , 369 | tnames : [ ] , 370 | .. 371 | } , 372 | X 373 | "# 374 | ); 375 | 376 | aeqiws!( 377 | pgts!({ .. }, <'a: 'b + 'c, 'b: 'c, 'c> X), 378 | r#" 379 | { 380 | constr : [ 'a : 'b + 'c , 'b : 'c , 'c , ] , 381 | params : [ 'a , 'b , 'c , ] , 382 | ltimes : [ 'a , 'b , 'c , ] , 383 | tnames : [ ] , 384 | .. 385 | } , 386 | X 387 | "# 388 | ); 389 | 390 | aeqiws!( 391 | pgts!({ .. }, From<&'a str>> X), 392 | if cfg!(feature="parse-generics-poc") { 393 | r#" 394 | { 395 | constr : [ T : ? Sized + Clone + Copy 396 | + for < 'a > From < &'a str > , ] , 397 | params : [ T , ] , 398 | ltimes : [ ] , 399 | tnames : [ T , ] , 400 | .. 401 | } , 402 | X 403 | "# 404 | } else { 405 | r#" 406 | { 407 | constr : [ T : ? Sized + Clone + Copy 408 | + for < 'a > From < & 'a str > , ] , 409 | params : [ T , ] , 410 | ltimes : [ ] , 411 | tnames : [ T , ] , 412 | .. 413 | } , 414 | X 415 | "# 416 | } 417 | ); 418 | } 419 | 420 | #[test] 421 | fn test_passthru() { 422 | macro_rules! emit { 423 | ( 424 | $fn_name:ident 425 | { 426 | constr: [$($constr:tt)*], 427 | $($_rest:tt)* 428 | }, 429 | $($_tail:tt)* 430 | ) => { 431 | as_item! { 432 | #[allow(dead_code)] 433 | fn $fn_name<$($constr)*>() { panic!("BOOM!"); } 434 | } 435 | }; 436 | } 437 | 438 | parse_generics_shim! { { .. }, then emit!{a}, X } 439 | parse_generics_shim! { { .. }, then emit!{b}, <> X } 440 | parse_generics_shim! { { .. }, then emit!{c}, X } 441 | parse_generics_shim! { { .. }, then emit!{d}, X } 442 | parse_generics_shim! { { .. }, then emit!{e}, X } 443 | parse_generics_shim! { { .. }, then emit!{f}, X } 444 | parse_generics_shim! { { .. }, then emit!{g}, X } 445 | parse_generics_shim! { { .. }, then emit!{g2}, X } 446 | parse_generics_shim! { { .. }, then emit!{h}, <'a> X } 447 | parse_generics_shim! { { .. }, then emit!{i}, <'a,> X } 448 | parse_generics_shim! { { .. }, then emit!{j}, <'a, 'b> X } 449 | parse_generics_shim! { { .. }, then emit!{k}, <'a, 'b,> X } 450 | parse_generics_shim! { { .. }, then emit!{l}, <'a, 'b: 'a> X } 451 | parse_generics_shim! { { .. }, then emit!{l2}, <'a, 'b: 'a, 'c: 'a + 'b> X } 452 | parse_generics_shim! { { .. }, then emit!{m}, <'a, T: 'a + Copy> X } 453 | parse_generics_shim! { { .. }, then emit!{m2}, <'a, T: 'a + Copy + Clone> X } 454 | parse_generics_shim! { { .. }, then emit!{n}, X } 455 | parse_generics_shim! { { .. }, then emit!{o}, > X } 456 | 457 | let _ = "the rustc parser is stoopid"; 458 | } 459 | -------------------------------------------------------------------------------- /parse-generics-shim/tests/parse_where.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 11 | #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 12 | #[macro_use] extern crate parse_generics_shim; 13 | 14 | macro_rules! as_item { ($i:item) => { $i } } 15 | 16 | macro_rules! aeqiws { 17 | ($lhs:expr, $rhs:expr) => { 18 | { 19 | let lhs = $lhs; 20 | let rhs = $rhs; 21 | let lhs_words = $lhs.split_whitespace(); 22 | let rhs_words = $rhs.split_whitespace(); 23 | for (i, (l, r)) in lhs_words.zip(rhs_words).enumerate() { 24 | if l != r { 25 | panic!("assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`, at word {}, `{:?}` != `{:?}`)", lhs, rhs, i, l, r); 26 | } 27 | } 28 | } 29 | }; 30 | } 31 | 32 | macro_rules! pwts { 33 | ($fields:tt, $($body:tt)*) => { 34 | parse_where_shim! { 35 | $fields, 36 | then stringify!(), 37 | $($body)* 38 | } 39 | }; 40 | } 41 | 42 | #[test] 43 | fn test_no_where() { 44 | aeqiws!( 45 | pwts!({..}, X), 46 | r#" 47 | { clause : [ ] , preds : [ ] , .. } , 48 | X 49 | "# 50 | ); 51 | 52 | aeqiws!( 53 | pwts!({ clause, preds }, X), 54 | r#" 55 | { clause : [ ] , preds : [ ] , } , 56 | X 57 | "# 58 | ); 59 | 60 | aeqiws!( 61 | pwts!({ preds }, X), 62 | r#" 63 | { preds : [ ] , } , 64 | X 65 | "# 66 | ); 67 | } 68 | 69 | #[test] 70 | fn test_where() { 71 | aeqiws!( 72 | pwts!({..}, where 'a: 'b; X), 73 | r#" 74 | { 75 | clause : [ where 'a : 'b , ] , 76 | preds : [ 'a : 'b , ] , 77 | .. 78 | } , 79 | ; X 80 | "# 81 | ); 82 | 83 | aeqiws!( 84 | pwts!({..}, where T: 'a + U; X), 85 | r#" 86 | { 87 | clause : [ where T : 'a + U , ] , 88 | preds : [ T : 'a + U , ] , 89 | .. 90 | } , 91 | ; X 92 | "# 93 | ); 94 | 95 | aeqiws!( 96 | pwts!({..}, where 'a: 'b, T: 'a + U; X), 97 | r#" 98 | { 99 | clause : [ where 'a : 'b , T : 'a + U , ] , 100 | preds : [ 'a : 'b , T : 'a + U , ] , 101 | .. 102 | } , 103 | ; X 104 | "# 105 | ); 106 | 107 | aeqiws!( 108 | pwts!({..}, where 'a: 'b, T: 'a + U, {} X), 109 | r#" 110 | { 111 | clause : [ where 'a : 'b , T : 'a + U , ] , 112 | preds : [ 'a : 'b , T : 'a + U , ] , 113 | .. 114 | } , 115 | { } X 116 | "# 117 | ); 118 | 119 | aeqiws!( 120 | pwts!({..}, where for<> T: 'a; X), 121 | r#" 122 | { 123 | clause : [ where T : 'a , ] , 124 | preds : [ T : 'a , ] , 125 | .. 126 | } , 127 | ; X 128 | "# 129 | ); 130 | 131 | aeqiws!( 132 | pwts!({..}, where for<'a> T: 'a; X), 133 | r#" 134 | { 135 | clause : [ where for < 'a , > T : 'a , ] , 136 | preds : [ for < 'a , > T : 'a , ] , 137 | .. 138 | } , 139 | ; X 140 | "# 141 | ); 142 | 143 | aeqiws!( 144 | pwts!({..}, where for<'a: 'b> T: 'a; X), 145 | r#" 146 | { 147 | clause : [ where for < 'a : 'b , > T : 'a , ] , 148 | preds : [ for < 'a : 'b , > T : 'a , ] , 149 | .. 150 | } , 151 | ; X 152 | "# 153 | ); 154 | 155 | aeqiws!( 156 | pwts!({..}, where 'a: 'b, for<'a: 'b> T: 'a, 'c: 'a + 'b; X), 157 | r#" 158 | { 159 | clause : [ where 'a : 'b , for < 'a : 'b , > T : 'a , 'c : 'a + 'b , ] , 160 | preds : [ 'a : 'b , for < 'a : 'b , > T : 'a , 'c : 'a + 'b , ] , 161 | .. 162 | } , 163 | ; X 164 | "# 165 | ); 166 | } 167 | -------------------------------------------------------------------------------- /parse-macros/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /parse-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parse-macros" 3 | version = "0.1.2" 4 | authors = ["Daniel Keep "] 5 | 6 | description = "Provides macros for parsing Rust constructs such as enums and structs." 7 | repository = "https://github.com/DanielKeep/rust-parse-generics" 8 | documentation = "https://danielkeep.github.io/rust-parse-generics/doc/parse_macros/index.html" 9 | keywords = ["macro", "parse", "enum", "struct"] 10 | license = "MIT/Apache-2.0" 11 | 12 | build = "build.rs" 13 | 14 | [features] 15 | use-parse-generics-poc = [ 16 | "parse-generics-poc", 17 | "parse-generics-shim/use-parse-generics-poc", 18 | ] 19 | 20 | [dependencies] 21 | parse-generics-shim = { version = "0.1.0", path = "../parse-generics-shim" } 22 | 23 | [dependencies.parse-generics-poc] 24 | version = "0.1.0" 25 | optional = true 26 | path = "../parse-generics-poc" 27 | 28 | [build-dependencies] 29 | rustc_version = "0.1.7" 30 | 31 | [dev-dependencies] 32 | custom_derive = "0.1.4" 33 | serde = "0.6.11" 34 | serde_json = "0.6.0" 35 | -------------------------------------------------------------------------------- /parse-macros/build.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | extern crate rustc_version; 11 | use rustc_version::{version_meta, Channel}; 12 | 13 | fn main() { 14 | // Set cfg flags depending on release channel 15 | let channel = match version_meta().channel { 16 | Channel::Stable => "stable", 17 | Channel::Beta => "beta", 18 | Channel::Nightly | Channel::Dev => "nightly", 19 | }; 20 | println!("cargo:rustc-cfg=channel={:?}", channel); 21 | } 22 | -------------------------------------------------------------------------------- /parse-macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | /*! 11 | This crate provides high-level macros for parsing various Rust constructs. 12 | 13 | Specifically, these macros are concerned with taking Rust source constructs and rewriting them into a format which is more easily consumable by `macro_rules!` macros. 14 | 15 | 28 | 37 | 38 | ## Table of Contents 39 | 40 | - [`parse_enum!`](#parse_enum) 41 | - [`parse_item!`](#parse_item) 42 | - [`parse_struct!`](#parse_struct) 43 | - [Using `parse-macros`](#using-parse-macros) 44 | 45 | ## `parse_enum!` 46 | 47 | ```ignore 48 | macro_rules! parse_enum { 49 | ( 50 | then $cb:ident!( $($cb_arg:tt)* ), 51 | $($body:tt)* 52 | ) => { ... }; 53 | } 54 | ``` 55 | 56 | Parses `$body` as an `enum`, invoking the macro `$cb` with the result. The general form of the expansion is: 57 | 58 | ```ignore 59 | $cb! { 60 | $($cb_arg)* 61 | enum { 62 | attrs: $attrs:tt, 63 | vis: $vis:tt, 64 | name: $name:ident, 65 | generics: $generics:tt, 66 | where: $where_:tt, 67 | variants: $variants:tt, 68 | num_variants: $num_variants:tt, 69 | } 70 | } 71 | ``` 72 | 73 | ### Callback 74 | 75 | `$cb_name` and `$cb_arg` specify the macro to invoke with the result of parsing. Note that `$cb_arg` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`. 76 | 77 | ### Fields 78 | 79 | The expansion contains the following fields: 80 | 81 | - `$attrs`: a `[ .. ]`-delimited list of attributes. *e.g.*: `[ #[doc="Does a thing"] #[repr(u8)] ]`. 82 | 83 | - `$vis`: a `( .. )`-delimited visibility annotation. *e.g.*: `()`, `(pub)`. 84 | 85 | - `$name`: the `enum`'s name as an identifier. *e.g.*: `Option`. 86 | 87 | - `$generics`: the `{ .. }`-delimited output of `parse_generics_shim!` for the `enum`, containing the `constr`, `params`, `ltimes`, and `tnames` fields: 88 | 89 | ```ignore 90 | generics: { 91 | constr: $constr:tt, 92 | params: $params:tt, 93 | ltimes: $ltimes:tt, 94 | tnames: $tnames:tt, 95 | } 96 | ``` 97 | 98 | - `$constr`: a `[ .. ]`-delimited, comma-terminated list of generic constraints. *e.g.* `['a, 'b: 'a, T, U: 'a + Copy,]`. 99 | 100 | - `$params`: a `[ .. ]`-delimited, comma-terminated list of generic parameter names. *e.g.* `['a, 'b, T, U,]`. 101 | 102 | - `$ltimes`: a `[ .. ]`-delimited, comma-terminated list of generic lifetime parameters. *e.g.* `['a, 'b,]`. 103 | 104 | - `$tnames`: a `[ .. ]`-delimited, comma-terminated list of generic type parameters. *e.g.* `[T, U,]`. 105 | 106 | - `$where_`: the `{ .. }`-delimited output of `parse_where_shim!` for the `enum`, containing the `clause`, and `preds` fields: 107 | 108 | ```ignore 109 | where: { 110 | clause: $clause:tt, 111 | preds: $preds:tt, 112 | } 113 | ``` 114 | 115 | - `$clause`: a `[ .. ]`-delimited, comma-terminated clause, including the `where` keyword. If the clause is empty, the `where` keyword is omitted, and the brackets are empty. *e.g.* `[]`, `[ where for<'a> T: Fn(&'a i32), ]`. 116 | 117 | - `$preds`: a `[ .. ]`-delimited, comma-terminated list of clause predicates. *e.g.* `[]`, `[ for<'a> T: Fn(&'a i32), ]`. 118 | 119 | - `$variants`: a `[ .. ]`-delimited, comma-terminated list of variants (described below). 120 | 121 | - `$num_variants`: the number of variants in the `enum`. *e.g.* `2`. 122 | 123 | Each variant has the following form: 124 | 125 | ```ignore 126 | { 127 | ord: ($vord_index:tt, $vord_ident:ident), 128 | attrs: $vattrs:tt, 129 | kind: $vkind:ident, 130 | name: $vname:ident, 131 | fields: $vfields:tt, 132 | num_fields: $vnum_fields:tt, 133 | } 134 | ``` 135 | 136 | - `$vord_index`: the 0-based ordinal for this variant. *e.g.* `1`. 137 | 138 | - `$vord_ident`: an identifier guaranteed to be unique relative to other variants *for the same `enum`*. Identifiers are *not* guaranteed to be unique between different `parse_enum!` invocations. *e.g.* `_ord_01`. 139 | 140 | - `$vattrs`: a `[ .. ]`-delimited list of attributes attached to the variant. *e.g.* `[ #[doc="A variant unlike the rest."] ]`. 141 | 142 | - `$vkind`: one of `unitary`, `tuple`, or `record`. 143 | 144 | - `$vname`: the variant's name as an identifier. *e.g.* `None`. 145 | 146 | - `$vfields`: a `[ .. ]`-delimited, comma-terminated list of fields (described below). 147 | 148 | - `$vnum_fields`: the number of fields in the variant. *e.g.* `1`. 149 | 150 | Variant fields have the following form: 151 | 152 | ```ignore 153 | { 154 | ord: ($ford_index:tt, $ford_ident:ident), 155 | attrs: $fattrs:tt, 156 | vis: $fvis:tt, 157 | ty: $fty:ty, 158 | 159 | // **NOTE**: only exists for *record* variant fields: 160 | name: $fname:ident, 161 | } 162 | ``` 163 | 164 | - `$ford_index`: the 0-based ordinal for this variant field. *e.g.* `1`. 165 | 166 | - `$ford_ident`: an identifier guaranteed to be unique relative to other fields *for the same variant*. Identifiers are *not* guaranteed to be unique between different `parse_enum!` invocations, or between variants in the same invocation. *e.g.* `_ord_01`. 167 | 168 | - `$fattrs`: a `[ .. ]`-delimited list of attributes attached to the variant field. *e.g.* `[ #[doc="A part of the whole."] ]`. 169 | 170 | - `$fvis`: a `( .. )`-delimited visibility annotation. *e.g.*: `()`, `(pub)`. 171 | 172 | - `$fty`: the type of the variant field. 173 | 174 | - `$fname`: the variant field's name as an identifier. *e.g.* `part`. 175 | 176 | ### Example 177 | 178 | ```rust 179 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 180 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 181 | # #[macro_use] extern crate parse_generics_shim; 182 | # #[macro_use] extern crate parse_macros; 183 | # fn main() { 184 | # assert_eq!( ( 185 | parse_enum! { 186 | then stringify!(output:), 187 | /// The `Option` type. 188 | pub enum Option { 189 | /// No value. 190 | None, 191 | /// Some value `T`. 192 | Some(T), 193 | /// File could not be found. 194 | FileNotFound { path: PathBuf }, 195 | } 196 | } 197 | 198 | // Expands to: 199 | # /* 200 | stringify!( 201 | # */ 202 | # ).replace(char::is_whitespace, "") , r#" 203 | output: 204 | enum { 205 | attrs: [ #[doc=r"The `Option` type."] ], 206 | vis: (pub), 207 | name: Option, 208 | generics: { 209 | constr: [T,], 210 | params: [T,], 211 | ltimes: [], 212 | tnames: [T,], 213 | }, 214 | where: { 215 | clause: [], 216 | preds: [], 217 | }, 218 | variants: [ 219 | { 220 | ord: (0, _ord_00), 221 | attrs: [ #[doc=r"No value."] ], 222 | kind: unitary, 223 | name: None, 224 | fields: [], 225 | num_fields: 0, 226 | }, 227 | { 228 | ord: (1, _ord_01), 229 | attrs: [ #[doc=r"Some value `T`."] ], 230 | kind: tuple, 231 | name: Some, 232 | fields: [ 233 | { 234 | ord: (0, _ord_00), 235 | attrs: [], 236 | vis: (), 237 | ty: T, 238 | }, 239 | ], 240 | num_fields: 1, 241 | }, 242 | { 243 | ord: (2, _ord_02), 244 | attrs: [ #[doc=r"File could not be found."] ], 245 | kind: record, 246 | name: FileNotFound, 247 | fields: [ 248 | { 249 | ord: (0, _ord_00), 250 | attrs: [], 251 | vis: (), 252 | ty: PathBuf, 253 | name: path, 254 | }, 255 | ], 256 | num_fields: 1, 257 | }, 258 | ], 259 | num_variants: 3, 260 | } 261 | # "#.replace(char::is_whitespace, "")); /* 262 | ) 263 | # */ } 264 | ``` 265 | 266 | ## `parse_item!` 267 | 268 | ```ignore 269 | macro_rules! parse_item { 270 | ( 271 | then $cb:ident!( $($cb_arg:tt)* ), 272 | $($body:tt)* 273 | ) => { ... }; 274 | } 275 | ``` 276 | 277 | Parses `$body` as an item, invoking the macro `$cb` with the result. This forwards to the appropriate `parse_*!` macro, depending on what kind of item is in `$body`. 278 | 279 | See [`parse_enum!`](#parse_enum), and [`parse_struct!`](#parse_struct) for more details. 280 | 281 | ## `parse_struct!` 282 | 283 | ```ignore 284 | macro_rules! parse_struct { 285 | ( 286 | then $cb:ident!( $($cb_arg:tt)* ), 287 | $($body:tt)* 288 | ) => { ... }; 289 | } 290 | ``` 291 | 292 | Parses `$body` as a `struct`, invoking the macro `$cb` with the result. The general form of the expansion is: 293 | 294 | ```ignore 295 | $cb! { 296 | $($cb_arg)* 297 | struct { 298 | attrs: $attrs:tt, 299 | vis: $vis:tt, 300 | name: $name:ident, 301 | generics: $generics:tt, 302 | where: $where_:tt, 303 | kind: $kind:ident, 304 | fields: $fields:tt, 305 | num_fields: $num_fields:tt, 306 | } 307 | } 308 | ``` 309 | 310 | ### Callback 311 | 312 | `$cb_name` and `$cb_arg` specify the macro to invoke with the result of parsing. Note that `$cb_arg` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`. 313 | 314 | ### Fields 315 | 316 | The expansion contains the following fields: 317 | 318 | - `$attrs`: a `[ .. ]`-delimited list of attributes. *e.g.*: `[ #[doc="Does a thing"] #[repr(C)] ]`. 319 | 320 | - `$vis`: a `( .. )`-delimited visibility annotation. *e.g.*: `()`, `(pub)`. 321 | 322 | - `$name`: the `struct`'s name as an identifier. *e.g.*: `Option`. 323 | 324 | - `$generics`: the `{ .. }`-delimited output of `parse_generics_shim!` for the `struct`, containing the `constr`, `params`, `ltimes`, and `tnames` fields: 325 | 326 | ```ignore 327 | generics: { 328 | constr: $constr:tt, 329 | params: $params:tt, 330 | ltimes: $ltimes:tt, 331 | tnames: $tnames:tt, 332 | } 333 | ``` 334 | 335 | - `$constr`: a `[ .. ]`-delimited, comma-terminated list of generic constraints. *e.g.* `['a, 'b: 'a, T, U: 'a + Copy,]`. 336 | 337 | - `$params`: a `[ .. ]`-delimited, comma-terminated list of generic parameter names. *e.g.* `['a, 'b, T, U,]`. 338 | 339 | - `$ltimes`: a `[ .. ]`-delimited, comma-terminated list of generic lifetime parameters. *e.g.* `['a, 'b,]`. 340 | 341 | - `$tnames`: a `[ .. ]`-delimited, comma-terminated list of generic type parameters. *e.g.* `[T, U,]`. 342 | 343 | - `$where_`: the `{ .. }`-delimited output of `parse_where_shim!` for the `struct`, containing the `preds` field: 344 | 345 | ```ignore 346 | where: { 347 | preds: $preds, 348 | } 349 | ``` 350 | 351 | - `$preds`: a `[ .. ]`-delimited, comma-separated list of clause predicates. *e.g.* `[ for<'a> T: Fn(&'a i32), ]`. 352 | 353 | - `$kind`: one of `unitary`, `tuple`, or `record`. These correspond to the three kinds of `struct` definitions: `struct Unitary;`, `struct Tuple(..);` and `struct Record { .. }`. 354 | 355 | - `$fields`: a `[ .. ]`-delimited, comma-terminated list of fields (described below). 356 | 357 | - `$num_fields`: the number of fields in the `struct`. *e.g.* `2`. 358 | 359 | `struct` fields have the following form: 360 | 361 | ```ignore 362 | { 363 | ord: ($ford_index:tt, $ford_ident:ident), 364 | attrs: $fattrs:tt, 365 | vis: $fvis:tt, 366 | ty: $fty:ty, 367 | 368 | // **NOTE**: only exists for *record* `struct` fields: 369 | name: $fname:ident, 370 | } 371 | ``` 372 | 373 | - `$ford_index`: the 0-based ordinal for this `struct` field. *e.g.* `1`. 374 | 375 | - `$ford_ident`: an identifier guaranteed to be unique relative to other fields *for the same `struct`*. Identifiers are *not* guaranteed to be unique between different `parse_struct!` invocations. *e.g.* `_ord_01`. 376 | 377 | - `$fattrs`: a `[ .. ]`-delimited list of attributes attached to the `struct` field. *e.g.* `[ #[doc="The amount of green-ness."] ]`. 378 | 379 | - `$fvis`: a `( .. )`-delimited visibility annotation. *e.g.*: `()`, `(pub)`. 380 | 381 | - `$fty`: the type of the `struct` field. 382 | 383 | - `$fname`: the `struct` field's name as an identifier. *e.g.* `green`. 384 | 385 | ### Example 386 | 387 | ```rust 388 | # #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))] 389 | # #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))] 390 | # #[macro_use] extern crate parse_generics_shim; 391 | # #[macro_use] extern crate parse_macros; 392 | # fn main() { 393 | # assert_eq!( ( 394 | parse_struct! { 395 | then stringify!(output:), 396 | /// Represents a colour. 397 | pub struct Rgb { 398 | /// The degree of red-ness. 399 | r: Ch, 400 | /// How eco-friendly is this colour? 401 | g: Ch, 402 | /// Maybe it's blue, maybe it's not? 403 | b: Option, 404 | } 405 | } 406 | 407 | // Expands to: 408 | # /* 409 | stringify!( 410 | # */ 411 | # ).replace(char::is_whitespace, "") , r#" 412 | output: 413 | struct { 414 | attrs: [ #[doc=r"Represents a colour."] ], 415 | vis: (pub), 416 | name: Rgb, 417 | generics: { 418 | constr: [Ch,], 419 | params: [Ch,], 420 | ltimes: [], 421 | tnames: [Ch,], 422 | }, 423 | where: { 424 | clause: [], 425 | preds: [], 426 | }, 427 | kind: record, 428 | fields: [ 429 | { 430 | ord: (0, _ord_00), 431 | attrs: [ #[doc=r"The degree of red-ness."] ], 432 | vis: (), 433 | ty: Ch, 434 | name: r, 435 | }, 436 | { 437 | ord: (1, _ord_01), 438 | attrs: [ #[doc=r"How eco-friendly is this colour?"] ], 439 | vis: (), 440 | ty: Ch, 441 | name: g, 442 | }, 443 | { 444 | ord: (2, _ord_02), 445 | attrs: [ #[doc=r"Maybe it's blue, maybe it's not?"] ], 446 | vis: (), 447 | ty: Option, 448 | name: b, 449 | }, 450 | ], 451 | num_fields: 3, 452 | } 453 | # "#.replace(char::is_whitespace, "")); /* 454 | ) 455 | # */ } 456 | ``` 457 | 458 | ## Using `parse-macros` 459 | 460 | ### For Crate Authors 461 | 462 | Add the following to your `Cargo.toml` manifest: 463 | 464 | ```toml 465 | [features] 466 | use-parse-generics-poc = [ 467 | "parse-generics-poc", 468 | "parse-macros/use-parse-generics-poc", 469 | ] 470 | 471 | [dependencies] 472 | parse-generics-poc = { version = "0.1.0", optional = true } 473 | parse-macros = "0.1.0" 474 | ``` 475 | 476 | This allows your users to enable the proof-of-concept compiler plugin *through* your crate. You should also copy and modify the following section (replacing `whizzo` with your crate's name). 477 | 478 | ### For Crate Users 479 | 480 | Add the following to your `Cargo.toml` manifest: 481 | 482 | ```toml 483 | [features] 484 | use-parse-generics-poc = [ 485 | "whizzo/use-parse-generics-poc", 486 | "parse-generics-poc", 487 | "parse-macros/use-parse-generics-poc", 488 | ] 489 | 490 | [dependencies] 491 | whizzo = "0.1.0" 492 | parse-generics-poc = { version = "0.1.0", optional = true } 493 | parse-generics-shim = "0.1.0" 494 | parse-macros = "0.1.0" 495 | ``` 496 | 497 | Then, add the following to your crate's root module: 498 | 499 | ```ignore 500 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 501 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 502 | #[macro_use] extern crate parse_generics_shim; 503 | #[macro_use] extern crate parse_macros; 504 | #[macro_use] extern crate whizzo; 505 | ``` 506 | 507 | By default, this will use stable-but-inferior implementations of the generics-parsing macros. In particular, you cannot use lifetimes other than `'a` through `'z`, and macros may fail to expand for sufficiently complex inputs. 508 | 509 | If a macro fails to expand due to the "recursion limit", place the following attribute at the top of your crate's root module, and raise the number until the macro works: 510 | 511 | ```rust 512 | #![recursion_limit="32"] 513 | ``` 514 | 515 | If you are using a compatible nightly compiler, you can enable the fully-featured versions of the generics-parsing macros (see the proposed [RFC #1583](https://github.com/rust-lang/rfcs/pull/1583) for context). If you have followed the instructions above, this can be done by adding `--features=use-parse-generic-poc` to your `cargo build` command. 516 | 517 | The [documentation for `parse-generics-poc`](https://danielkeep.github.io/rust-parse-generics/doc/parse_generics_poc/index.html) will specify *which* nightly it is known to be compatible with. If you are using `rustup`, you can configure your crate to use the appropriate compiler using the following (replacing the date shown with the one listed in the `parse-generics-poc` documentation): 518 | 519 | ```sh 520 | rustup override add nightly-2016-04-06 521 | ``` 522 | */ 523 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 524 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 525 | #[macro_use] extern crate parse_generics_shim; 526 | 527 | #[macro_use] mod parse_enum; 528 | #[macro_use] mod parse_item; 529 | #[macro_use] mod parse_macros_util; 530 | #[macro_use] mod parse_struct; 531 | #[macro_use] mod parse_type_item; 532 | -------------------------------------------------------------------------------- /parse-macros/src/parse_enum.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[doc(hidden)] 11 | #[macro_export] 12 | macro_rules! parse_enum { 13 | ( 14 | then $cb:ident!$cb_arg:tt, 15 | $(#[$($attrs:tt)*])* pub enum $name:ident $($tail:tt)* 16 | ) => { 17 | parse_generics_shim! { 18 | { constr, params, ltimes, tnames }, 19 | then parse_enum! { 20 | @with_generics 21 | (($cb!$cb_arg), [$(#[$($attrs)*])*], (pub), $name), 22 | }, 23 | $($tail)* 24 | } 25 | }; 26 | 27 | ( 28 | then $cb:ident!$cb_arg:tt, 29 | $(#[$($attrs:tt)*])* enum $name:ident $($tail:tt)* 30 | ) => { 31 | parse_generics_shim! { 32 | { constr, params, ltimes, tnames }, 33 | then parse_enum! { 34 | @with_generics 35 | (($cb!$cb_arg), [$(#[$($attrs)*])*], (), $name), 36 | }, 37 | $($tail)* 38 | } 39 | }; 40 | 41 | ( 42 | @with_generics 43 | $prefix:tt, 44 | $generics:tt, 45 | $($tail:tt)* 46 | ) => { 47 | parse_where_shim! { 48 | { clause, preds }, then parse_enum! { 49 | @with_where 50 | $prefix, 51 | $generics, 52 | }, 53 | $($tail)* 54 | } 55 | }; 56 | 57 | ( 58 | @with_where 59 | $prefix:tt, 60 | $generics:tt, 61 | $where_:tt, 62 | { $($body:tt)* } 63 | ) => { 64 | parse_enum! { 65 | @parse_variants 66 | ($prefix, $generics, $where_), 67 | [], 68 | [], 69 | { $($body)*, }, 70 | 0, _ord_00 71 | } 72 | }; 73 | 74 | ( 75 | @parse_variants 76 | ( 77 | ( 78 | $cb:tt, 79 | $attrs:tt, 80 | $vis:tt, 81 | $name:ident 82 | ), 83 | $generics:tt, 84 | $where_:tt 85 | ), 86 | $variants:tt, 87 | $_attrs:tt, 88 | { $(,)* }, 89 | $ord:tt, $_ord_ident:tt 90 | ) => { 91 | parse_macros_util! { 92 | @call $cb, 93 | enum { 94 | attrs: $attrs, 95 | vis: $vis, 96 | name: $name, 97 | generics: $generics, 98 | where: $where_, 99 | variants: $variants, 100 | num_variants: $ord, 101 | } 102 | } 103 | }; 104 | 105 | ( 106 | @parse_variants 107 | $prefix2:tt, 108 | $variants:tt, 109 | [$($attrs:tt)*], 110 | { #[$($attr:tt)*] $($tail:tt)* }, 111 | $ord:tt, $ord_ident:tt 112 | ) => { 113 | parse_enum! { 114 | @parse_variants 115 | $prefix2, 116 | $variants, 117 | [$($attrs)* #[$($attr)*]], 118 | { $($tail)* }, 119 | $ord, $ord_ident 120 | } 121 | }; 122 | 123 | ( 124 | @parse_variants 125 | $prefix2:tt, 126 | [$($variants:tt)*], 127 | $attrs:tt, 128 | { $vname:ident, $($tail:tt)* }, 129 | $ord:tt, $ord_ident:tt 130 | ) => { 131 | parse_macros_util! { 132 | @inc_ord_ident 133 | (parse_enum! { 134 | @parse_variants 135 | $prefix2, 136 | [ 137 | $($variants)* 138 | { 139 | ord: ($ord, $ord_ident), 140 | attrs: $attrs, 141 | kind: unitary, 142 | name: $vname, 143 | fields: [], 144 | num_fields: 0, 145 | }, 146 | ], 147 | [], 148 | { $($tail)* }, 149 | }), 150 | $ord 151 | } 152 | }; 153 | 154 | ( 155 | @parse_variants 156 | $prefix2:tt, 157 | $variants:tt, 158 | $attrs:tt, 159 | { $vname:ident($($body:tt)*), $($tail:tt)* }, 160 | $ord:tt, $ord_ident:tt 161 | ) => { 162 | parse_enum! { 163 | @parse_tuple_fields 164 | ($prefix2, $variants, $attrs, $vname, ($ord, $ord_ident), { $($tail)* }), 165 | [], 166 | [], 167 | ($($body)*,), 168 | 0, _ord_00 169 | } 170 | }; 171 | 172 | ( 173 | @parse_variants 174 | $prefix2:tt, 175 | $variants:tt, 176 | $attrs:tt, 177 | { $vname:ident { $($body:tt)* }, $($tail:tt)* }, 178 | $ord:tt, $ord_ident:tt 179 | ) => { 180 | parse_enum! { 181 | @parse_record_fields 182 | ($prefix2, $variants, $attrs, $vname, ($ord, $ord_ident), { $($tail)* }), 183 | [], 184 | [], 185 | { $($body)*, }, 186 | 0, _ord_00 187 | } 188 | }; 189 | 190 | ( 191 | @parse_tuple_fields 192 | ( 193 | $prefix2:tt, 194 | [$($variants:tt)*], 195 | $attrs:tt, 196 | $vname:ident, 197 | ($ord:tt, $ord_ident:tt), 198 | $tail:tt 199 | ), 200 | $fields:tt, 201 | $_fattrs:tt, 202 | ( $(,)* ), 203 | $ford:tt, $ford_ident:tt 204 | ) => { 205 | parse_macros_util! { 206 | @inc_ord_ident 207 | (parse_enum! { 208 | @parse_variants 209 | $prefix2, 210 | [ 211 | $($variants)* 212 | { 213 | ord: ($ord, $ord_ident), 214 | attrs: $attrs, 215 | kind: tuple, 216 | name: $vname, 217 | fields: $fields, 218 | num_fields: $ford, 219 | }, 220 | ], 221 | [], 222 | $tail, 223 | }), 224 | $ord 225 | } 226 | }; 227 | 228 | ( 229 | @parse_tuple_fields 230 | $prefix3:tt, 231 | $fields:tt, 232 | [$($attrs:tt)*], 233 | (#[$($attr:tt)*] $($tail:tt)*), 234 | $ord:tt, $ord_ident:tt 235 | ) => { 236 | parse_enum! { 237 | @parse_tuple_fields 238 | $prefix3, 239 | $fields, 240 | [$($attrs)* #[$($attr)*]], 241 | ($($tail)*), 242 | $ord, $ord_ident:tt 243 | } 244 | }; 245 | 246 | ( 247 | @parse_tuple_fields 248 | $prefix3:tt, 249 | [$($fields:tt)*], 250 | $attrs:tt, 251 | (pub $fty:ty, $($tail:tt)*), 252 | $ord:tt, $ord_ident:tt 253 | ) => { 254 | parse_macros_util! { 255 | @inc_ord_ident 256 | (parse_enum! { 257 | @parse_tuple_fields 258 | $prefix3, 259 | [ 260 | $($fields)* 261 | { 262 | ord: ($ord, $ord_ident), 263 | attrs: $attrs, 264 | vis: (pub), 265 | ty: $fty, 266 | }, 267 | ], 268 | [], 269 | ($($tail)*), 270 | }), 271 | $ord 272 | } 273 | }; 274 | 275 | ( 276 | @parse_tuple_fields 277 | $prefix3:tt, 278 | [$($fields:tt)*], 279 | $attrs:tt, 280 | ($fty:ty, $($tail:tt)*), 281 | $ord:tt, $ord_ident:tt 282 | ) => { 283 | parse_macros_util! { 284 | @inc_ord_ident 285 | (parse_enum! { 286 | @parse_tuple_fields 287 | $prefix3, 288 | [ 289 | $($fields)* 290 | { 291 | ord: ($ord, $ord_ident), 292 | attrs: $attrs, 293 | vis: (), 294 | ty: $fty, 295 | }, 296 | ], 297 | [], 298 | ($($tail)*), 299 | }), 300 | $ord 301 | } 302 | }; 303 | 304 | ( 305 | @parse_record_fields 306 | ( 307 | $prefix2:tt, 308 | [$($variants:tt)*], 309 | $attrs:tt, 310 | $vname:ident, 311 | ($ord:tt, $ord_ident:tt), 312 | $tail:tt 313 | ), 314 | $fields:tt, 315 | $_fattrs:tt, 316 | { $(,)* }, 317 | $ford:tt, $ford_ident:tt 318 | ) => { 319 | parse_macros_util! { 320 | @inc_ord_ident 321 | (parse_enum! { 322 | @parse_variants 323 | $prefix2, 324 | [ 325 | $($variants)* 326 | { 327 | ord: ($ord, $ord_ident), 328 | attrs: $attrs, 329 | kind: record, 330 | name: $vname, 331 | fields: $fields, 332 | num_fields: $ford, 333 | }, 334 | ], 335 | [], 336 | $tail, 337 | }), 338 | $ord 339 | } 340 | }; 341 | 342 | ( 343 | @parse_record_fields 344 | $prefix3:tt, 345 | $fields:tt, 346 | [$($attrs:tt)*], 347 | { #[$($attr:tt)*] $($tail:tt)* }, 348 | $ord:tt, $ord_ident:tt 349 | ) => { 350 | parse_enum! { 351 | @parse_record_fields 352 | $prefix3, 353 | $fields, 354 | [$($attrs)* #[$($attr)*]], 355 | { $($tail)* }, 356 | $ord, $ord_ident 357 | } 358 | }; 359 | 360 | ( 361 | @parse_record_fields 362 | $prefix3:tt, 363 | [$($fields:tt)*], 364 | $attrs:tt, 365 | { pub $fname:ident: $fty:ty, $($tail:tt)* }, 366 | $ord:tt, $ord_ident:tt 367 | ) => { 368 | parse_macros_util! { 369 | @inc_ord_ident 370 | (parse_enum! { 371 | @parse_record_fields 372 | $prefix3, 373 | [ 374 | $($fields)* 375 | { 376 | ord: ($ord, $ord_ident), 377 | attrs: $attrs, 378 | vis: (pub), 379 | ty: $fty, 380 | name: $fname, 381 | }, 382 | ], 383 | [], 384 | { $($tail)* }, 385 | }), 386 | $ord 387 | } 388 | }; 389 | 390 | ( 391 | @parse_record_fields 392 | $prefix3:tt, 393 | [$($fields:tt)*], 394 | $attrs:tt, 395 | { $fname:ident: $fty:ty, $($tail:tt)* }, 396 | $ord:tt, $ord_ident:tt 397 | ) => { 398 | parse_macros_util! { 399 | @inc_ord_ident 400 | (parse_enum! { 401 | @parse_record_fields 402 | $prefix3, 403 | [ 404 | $($fields)* 405 | { 406 | ord: ($ord, $ord_ident), 407 | attrs: $attrs, 408 | vis: (), 409 | ty: $fty, 410 | name: $fname, 411 | }, 412 | ], 413 | [], 414 | { $($tail)* }, 415 | }), 416 | $ord 417 | } 418 | }; 419 | } 420 | -------------------------------------------------------------------------------- /parse-macros/src/parse_item.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[doc(hidden)] 11 | #[macro_export] 12 | macro_rules! parse_item { 13 | ( 14 | then $cb:ident!$cb_arg:tt, 15 | $(#[$($attrs:tt)*])* pub enum $($tail:tt)* 16 | ) => { 17 | parse_enum! { 18 | then $cb!$cb_arg, 19 | $(#[$($attrs)*])* pub enum $($tail)* 20 | } 21 | }; 22 | 23 | ( 24 | then $cb:ident!$cb_arg:tt, 25 | $(#[$($attrs:tt)*])* enum $($tail:tt)* 26 | ) => { 27 | parse_enum! { 28 | then $cb!$cb_arg, 29 | $(#[$($attrs)*])* enum $($tail)* 30 | } 31 | }; 32 | 33 | ( 34 | then $cb:ident!$cb_arg:tt, 35 | $(#[$($attrs:tt)*])* pub struct $($tail:tt)* 36 | ) => { 37 | parse_struct! { 38 | then $cb!$cb_arg, 39 | $(#[$($attrs)*])* pub struct $($tail)* 40 | } 41 | }; 42 | 43 | ( 44 | then $cb:ident!$cb_arg:tt, 45 | $(#[$($attrs:tt)*])* struct $($tail:tt)* 46 | ) => { 47 | parse_struct! { 48 | then $cb!$cb_arg, 49 | $(#[$($attrs)*])* struct $($tail)* 50 | } 51 | }; 52 | 53 | ( 54 | then $cb:ident!$cb_arg:tt, 55 | $(#[$($attrs:tt)*])* pub type $($tail:tt)* 56 | ) => { 57 | parse_type_item! { 58 | then $cb!$cb_arg, 59 | $(#[$($attrs)*])* pub type $($tail)* 60 | } 61 | }; 62 | 63 | ( 64 | then $cb:ident!$cb_arg:tt, 65 | $(#[$($attrs:tt)*])* type $($tail:tt)* 66 | ) => { 67 | parse_type_item! { 68 | then $cb!$cb_arg, 69 | $(#[$($attrs)*])* type $($tail)* 70 | } 71 | }; 72 | } 73 | -------------------------------------------------------------------------------- /parse-macros/src/parse_macros_util.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[doc(hidden)] 11 | #[macro_export] 12 | macro_rules! parse_macros_util { 13 | ( 14 | @call 15 | ($cb:ident!($($cb_arg:tt)*)), 16 | $($output:tt)* 17 | ) => { 18 | $cb!( 19 | $($cb_arg)* 20 | $($output)* 21 | ) 22 | }; 23 | 24 | ( 25 | @call 26 | ($cb:ident!{$($cb_arg:tt)*}), 27 | $($output:tt)* 28 | ) => { 29 | $cb! { 30 | $($cb_arg)* 31 | $($output)* 32 | } 33 | }; 34 | 35 | (@inc_ord_ident $cb:tt, 0) => { parse_macros_util!{ @call $cb, 1, _ord_01 } }; 36 | (@inc_ord_ident $cb:tt, 1) => { parse_macros_util!{ @call $cb, 2, _ord_02 } }; 37 | (@inc_ord_ident $cb:tt, 2) => { parse_macros_util!{ @call $cb, 3, _ord_03 } }; 38 | (@inc_ord_ident $cb:tt, 3) => { parse_macros_util!{ @call $cb, 4, _ord_04 } }; 39 | (@inc_ord_ident $cb:tt, 4) => { parse_macros_util!{ @call $cb, 5, _ord_05 } }; 40 | (@inc_ord_ident $cb:tt, 5) => { parse_macros_util!{ @call $cb, 6, _ord_06 } }; 41 | (@inc_ord_ident $cb:tt, 6) => { parse_macros_util!{ @call $cb, 7, _ord_07 } }; 42 | (@inc_ord_ident $cb:tt, 7) => { parse_macros_util!{ @call $cb, 8, _ord_08 } }; 43 | (@inc_ord_ident $cb:tt, 8) => { parse_macros_util!{ @call $cb, 9, _ord_09 } }; 44 | (@inc_ord_ident $cb:tt, 9) => { parse_macros_util!{ @call $cb, 10, _ord_10 } }; 45 | (@inc_ord_ident $cb:tt, 10) => { parse_macros_util!{ @call $cb, 11, _ord_11 } }; 46 | (@inc_ord_ident $cb:tt, 11) => { parse_macros_util!{ @call $cb, 12, _ord_12 } }; 47 | (@inc_ord_ident $cb:tt, 12) => { parse_macros_util!{ @call $cb, 13, _ord_13 } }; 48 | (@inc_ord_ident $cb:tt, 13) => { parse_macros_util!{ @call $cb, 14, _ord_14 } }; 49 | (@inc_ord_ident $cb:tt, 14) => { parse_macros_util!{ @call $cb, 15, _ord_15 } }; 50 | (@inc_ord_ident $cb:tt, 15) => { parse_macros_util!{ @call $cb, 16, _ord_16 } }; 51 | (@inc_ord_ident $cb:tt, 16) => { parse_macros_util!{ @call $cb, 17, _ord_17 } }; 52 | (@inc_ord_ident $cb:tt, 17) => { parse_macros_util!{ @call $cb, 18, _ord_18 } }; 53 | (@inc_ord_ident $cb:tt, 18) => { parse_macros_util!{ @call $cb, 19, _ord_19 } }; 54 | (@inc_ord_ident $cb:tt, 19) => { parse_macros_util!{ @call $cb, 20, _ord_20 } }; 55 | (@inc_ord_ident $cb:tt, 20) => { parse_macros_util!{ @call $cb, 21, _ord_21 } }; 56 | (@inc_ord_ident $cb:tt, 21) => { parse_macros_util!{ @call $cb, 22, _ord_22 } }; 57 | (@inc_ord_ident $cb:tt, 22) => { parse_macros_util!{ @call $cb, 23, _ord_23 } }; 58 | (@inc_ord_ident $cb:tt, 23) => { parse_macros_util!{ @call $cb, 24, _ord_24 } }; 59 | (@inc_ord_ident $cb:tt, 24) => { parse_macros_util!{ @call $cb, 25, _ord_25 } }; 60 | (@inc_ord_ident $cb:tt, 25) => { parse_macros_util!{ @call $cb, 26, _ord_26 } }; 61 | (@inc_ord_ident $cb:tt, 26) => { parse_macros_util!{ @call $cb, 27, _ord_27 } }; 62 | (@inc_ord_ident $cb:tt, 27) => { parse_macros_util!{ @call $cb, 28, _ord_28 } }; 63 | (@inc_ord_ident $cb:tt, 28) => { parse_macros_util!{ @call $cb, 29, _ord_29 } }; 64 | (@inc_ord_ident $cb:tt, 29) => { parse_macros_util!{ @call $cb, 30, _ord_30 } }; 65 | (@inc_ord_ident $cb:tt, 30) => { parse_macros_util!{ @call $cb, 31, _ord_31 } }; 66 | (@inc_ord_ident $cb:tt, 31) => { parse_macros_util!{ @call $cb, 32, _ord_32 } }; 67 | } 68 | -------------------------------------------------------------------------------- /parse-macros/src/parse_struct.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[doc(hidden)] 11 | #[macro_export] 12 | macro_rules! parse_struct { 13 | ( 14 | then $cb:ident!$cb_arg:tt, 15 | $(#[$($attrs:tt)*])* pub struct $name:ident $($tail:tt)* 16 | ) => { 17 | parse_generics_shim! { 18 | { constr, params, ltimes, tnames }, 19 | then parse_struct! { 20 | @with_generics 21 | (($cb!$cb_arg), [$(#[$($attrs)*])*], (pub), $name), 22 | }, 23 | $($tail)* 24 | } 25 | }; 26 | 27 | ( 28 | then $cb:ident!$cb_arg:tt, 29 | $(#[$($attrs:tt)*])* struct $name:ident $($tail:tt)* 30 | ) => { 31 | parse_generics_shim! { 32 | { constr, params, ltimes, tnames }, 33 | then parse_struct! { 34 | @with_generics 35 | (($cb!$cb_arg), [$(#[$($attrs)*])*], (), $name), 36 | }, 37 | $($tail)* 38 | } 39 | }; 40 | 41 | ( 42 | @with_generics 43 | $prefix:tt, 44 | $generics:tt, 45 | ($($body:tt)*) $($tail:tt)* 46 | ) => { 47 | parse_where_shim! { 48 | { clause, preds }, then parse_struct! { 49 | @with_where 50 | $prefix, $generics, 51 | }, 52 | $($tail)* ($($body)*) 53 | } 54 | }; 55 | 56 | ( 57 | @with_generics 58 | $prefix:tt, 59 | $generics:tt, 60 | $($tail:tt)* 61 | ) => { 62 | parse_where_shim! { 63 | { clause, preds }, then parse_struct! { 64 | @with_where 65 | $prefix, $generics, 66 | }, 67 | $($tail)* 68 | } 69 | }; 70 | 71 | ( 72 | @with_where 73 | ($cb:tt, $attrs:tt, $vis:tt, $name:ident), 74 | $generics:tt, 75 | $where_:tt, 76 | ; 77 | ) => { 78 | parse_macros_util! { 79 | @call $cb, 80 | struct { 81 | attrs: $attrs, 82 | vis: $vis, 83 | name: $name, 84 | generics: $generics, 85 | where: $where_, 86 | kind: unitary, 87 | fields: [], 88 | num_fields: 0, 89 | } 90 | } 91 | }; 92 | 93 | ( 94 | @with_where 95 | $prefix:tt, 96 | $generics:tt, 97 | $where_:tt, 98 | ; ($($body:tt)*) 99 | ) => { 100 | parse_struct! { 101 | @parse_fields 102 | ($prefix, $generics, $where_), 103 | [], 104 | [], 105 | ($($body)*,), 106 | 0, _ord_00 107 | } 108 | }; 109 | 110 | ( 111 | @with_where 112 | $prefix:tt, 113 | $generics:tt, 114 | $where_:tt, 115 | {$($body:tt)*} 116 | ) => { 117 | parse_struct! { 118 | @parse_fields 119 | ($prefix, $generics, $where_), 120 | [], 121 | [], 122 | {$($body)*,}, 123 | 0, _ord_00 124 | } 125 | }; 126 | 127 | ( 128 | @parse_fields 129 | ( 130 | ( 131 | $cb:tt, 132 | $attrs:tt, 133 | $vis:tt, 134 | $name:ident 135 | ), 136 | $generics:tt, 137 | $where_:tt 138 | ), 139 | $fields:tt, 140 | $_attrs:tt, 141 | ($(,)*), 142 | $ord:tt, $_ord_ident:tt 143 | ) => { 144 | parse_macros_util! { 145 | @call $cb, 146 | struct { 147 | attrs: $attrs, 148 | vis: $vis, 149 | name: $name, 150 | generics: $generics, 151 | where: $where_, 152 | kind: tuple, 153 | fields: $fields, 154 | num_fields: $ord, 155 | } 156 | } 157 | }; 158 | 159 | ( 160 | @parse_fields 161 | $prefix2:tt, 162 | $fields:tt, 163 | [$($attrs:tt)*], 164 | (#[$($attr:tt)*] $($tail:tt)*), 165 | $ord:tt, $ord_ident:tt 166 | ) => { 167 | parse_struct! { 168 | @parse_fields 169 | $prefix2, 170 | $fields, 171 | [$($attrs)* #[$($attr)*]], 172 | ($($tail)*), 173 | $ord, $ord_ident 174 | } 175 | }; 176 | 177 | ( 178 | @parse_fields 179 | $prefix2:tt, 180 | [$($fields:tt)*], 181 | $attrs:tt, 182 | (pub $fty:ty, $($tail:tt)*), 183 | $ord:tt, $ord_ident:tt 184 | ) => { 185 | parse_macros_util! { 186 | @inc_ord_ident 187 | (parse_struct! { 188 | @parse_fields 189 | $prefix2, 190 | [ 191 | $($fields)* 192 | { 193 | ord: ($ord, $ord_ident), 194 | attrs: $attrs, 195 | vis: (pub), 196 | ty: $fty, 197 | }, 198 | ], 199 | [], 200 | ($($tail)*), 201 | }), 202 | $ord 203 | } 204 | }; 205 | 206 | ( 207 | @parse_fields 208 | $prefix2:tt, 209 | [$($fields:tt)*], 210 | $attrs:tt, 211 | ($fty:ty, $($tail:tt)*), 212 | $ord:tt, $ord_ident:tt 213 | ) => { 214 | parse_macros_util! { 215 | @inc_ord_ident 216 | (parse_struct! { 217 | @parse_fields 218 | $prefix2, 219 | [ 220 | $($fields)* 221 | { 222 | ord: ($ord, $ord_ident), 223 | attrs: $attrs, 224 | vis: (), 225 | ty: $fty, 226 | }, 227 | ], 228 | [], 229 | ($($tail)*), 230 | }), 231 | $ord 232 | } 233 | }; 234 | 235 | ( 236 | @parse_fields 237 | ( 238 | ( 239 | $cb:tt, 240 | $attrs:tt, 241 | $vis:tt, 242 | $name:ident 243 | ), 244 | $generics:tt, 245 | $where_:tt 246 | ), 247 | $fields:tt, 248 | $_attrs:tt, 249 | { $(,)* }, 250 | $ord:tt, $_ord_ident:tt 251 | ) => { 252 | parse_macros_util! { 253 | @call $cb, 254 | struct { 255 | attrs: $attrs, 256 | vis: $vis, 257 | name: $name, 258 | generics: $generics, 259 | where: $where_, 260 | kind: record, 261 | fields: $fields, 262 | num_fields: $ord, 263 | } 264 | } 265 | }; 266 | 267 | ( 268 | @parse_fields 269 | $prefix2:tt, 270 | $fields:tt, 271 | [$($attrs:tt)*], 272 | { #[$($attr:tt)*] $($tail:tt)* }, 273 | $ord:tt, $ord_ident:tt 274 | ) => { 275 | parse_struct! { 276 | @parse_fields 277 | $prefix2, 278 | $fields, 279 | [$($attrs)* #[$($attr)*]], 280 | { $($tail)* }, 281 | $ord, $ord_ident 282 | } 283 | }; 284 | 285 | ( 286 | @parse_fields 287 | $prefix2:tt, 288 | [$($fields:tt)*], 289 | $attrs:tt, 290 | { pub $fname:ident: $fty:ty, $($tail:tt)* }, 291 | $ord:tt, $ord_ident:tt 292 | ) => { 293 | parse_macros_util! { 294 | @inc_ord_ident 295 | (parse_struct! { 296 | @parse_fields 297 | $prefix2, 298 | [ 299 | $($fields)* 300 | { 301 | ord: ($ord, $ord_ident), 302 | attrs: $attrs, 303 | vis: (pub), 304 | ty: $fty, 305 | name: $fname, 306 | }, 307 | ], 308 | [], 309 | {$($tail)*}, 310 | }), 311 | $ord 312 | } 313 | }; 314 | 315 | ( 316 | @parse_fields 317 | $prefix2:tt, 318 | [$($fields:tt)*], 319 | $attrs:tt, 320 | { $fname:ident: $fty:ty, $($tail:tt)* }, 321 | $ord:tt, $ord_ident:tt 322 | ) => { 323 | parse_macros_util! { 324 | @inc_ord_ident 325 | (parse_struct! { 326 | @parse_fields 327 | $prefix2, 328 | [ 329 | $($fields)* 330 | { 331 | ord: ($ord, $ord_ident), 332 | attrs: $attrs, 333 | vis: (), 334 | ty: $fty, 335 | name: $fname, 336 | }, 337 | ], 338 | [], 339 | {$($tail)*}, 340 | }), 341 | $ord 342 | } 343 | }; 344 | } 345 | -------------------------------------------------------------------------------- /parse-macros/src/parse_type_item.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #[doc(hidden)] 11 | #[macro_export] 12 | macro_rules! parse_type_item { 13 | ( 14 | then $cb:ident!$cb_arg:tt, 15 | $(#[$($attrs:tt)*])* pub type $name:ident $($tail:tt)* 16 | ) => { 17 | parse_generics_shim! { 18 | { constr, params, ltimes, tnames }, 19 | then parse_type_item! { 20 | @with_generics 21 | (($cb!$cb_arg), [$(#[$($attrs)*])*], (pub), $name), 22 | }, 23 | $($tail)* 24 | } 25 | }; 26 | 27 | ( 28 | then $cb:ident!$cb_arg:tt, 29 | $(#[$($attrs:tt)*])* type $name:ident $($tail:tt)* 30 | ) => { 31 | parse_generics_shim! { 32 | { constr, params, ltimes, tnames }, 33 | then parse_type_item! { 34 | @with_generics 35 | (($cb!$cb_arg), [$(#[$($attrs)*])*], (), $name), 36 | }, 37 | $($tail)* 38 | } 39 | }; 40 | 41 | ( 42 | @with_generics 43 | $prefix:tt, 44 | $generics:tt, 45 | $($tail:tt)* 46 | ) => { 47 | parse_where_shim! { 48 | { preds }, then parse_type_item! { 49 | @with_where 50 | $prefix, $generics, 51 | }, 52 | $($tail)* 53 | } 54 | }; 55 | 56 | ( 57 | @with_where 58 | ($cb:tt, $attrs:tt, $vis:tt, $name:ident), 59 | $generics:tt, 60 | $preds:tt, 61 | = $t:ty; 62 | ) => { 63 | parse_macros_util! { 64 | @call $cb, 65 | type { 66 | attrs: $attrs, 67 | vis: $vis, 68 | name: $name, 69 | generics: $generics, 70 | where: $preds, 71 | type: $t, 72 | } 73 | } 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /parse-macros/tests/derive_clone.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 11 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 12 | #[macro_use] extern crate parse_generics_shim; 13 | 14 | #[macro_use] extern crate custom_derive; 15 | #[macro_use] extern crate parse_macros; 16 | 17 | macro_rules! Clone_mac { 18 | ( 19 | () $($tail:tt)* 20 | ) => { 21 | parse_item! { 22 | then Clone_mac! { @item }, 23 | $($tail)* 24 | } 25 | }; 26 | 27 | ( 28 | @item 29 | enum { 30 | attrs: $_attrs:tt, 31 | vis: $_vis:tt, 32 | name: $name:ident, 33 | generics: { 34 | constr: [$($constr:tt)*], 35 | params: [$($params:tt)*], 36 | ltimes: $_ltimes:tt, 37 | tnames: [$($tnames:ident,)*], 38 | }, 39 | where: { 40 | clause: $_clause:tt, 41 | preds: [$($preds:tt)*], 42 | }, 43 | variants: [$($vars:tt,)*], 44 | $($_enum_tail:tt)* 45 | } 46 | ) => { 47 | Clone_mac! { 48 | @inject_where 49 | (impl<$($constr)*> Clone for $name<$($params)*>), 50 | where ($($tnames: Clone,)* $($preds)*) 51 | ({ 52 | fn clone(&self) -> Self { 53 | match *self { 54 | $( 55 | Clone_mac!(@var_match_pat $name, $vars) 56 | => Clone_mac!(@var_match_body $name, $vars), 57 | )* 58 | } 59 | } 60 | }) 61 | } 62 | }; 63 | 64 | ( 65 | @item 66 | struct { 67 | attrs: $_attrs:tt, 68 | vis: $_vis:tt, 69 | name: $name:ident, 70 | generics: { 71 | constr: [$($constr:tt)*], 72 | params: [$($params:tt)*], 73 | ltimes: $_ltimes:tt, 74 | tnames: [$($tnames:ident,)*], 75 | }, 76 | where: { 77 | clause: $_clause:tt, 78 | preds: [$($preds:tt)*], 79 | }, 80 | kind: unitary, 81 | fields: [], 82 | $($_struct_tail:tt)* 83 | } 84 | ) => { 85 | Clone_mac! { 86 | @inject_where 87 | (impl<$($constr)*> Clone for $name<$($params)*>), 88 | where ($($tnames: Clone,)* $($preds)*) 89 | ({ 90 | fn clone(&self) -> Self { 91 | $name 92 | } 93 | }) 94 | } 95 | }; 96 | 97 | ( 98 | @item 99 | struct { 100 | attrs: $_attrs:tt, 101 | vis: $_vis:tt, 102 | name: $name:ident, 103 | generics: { 104 | constr: [$($constr:tt)*], 105 | params: [$($params:tt)*], 106 | ltimes: $_ltimes:tt, 107 | tnames: [$($tnames:ident,)*], 108 | }, 109 | where: { 110 | clause: $_clause:tt, 111 | preds: [$($preds:tt)*], 112 | }, 113 | kind: tuple, 114 | fields: [$( 115 | { 116 | ord: ($_ford:tt, $ford_ident:ident), 117 | attrs: $_fattrs:tt, 118 | vis: $_fvis:tt, 119 | ty: $_fty:ty, 120 | }, 121 | )*], 122 | $($_struct_tail:tt)* 123 | } 124 | ) => { 125 | Clone_mac! { 126 | @inject_where 127 | (impl<$($constr)*> Clone for $name<$($params)*>), 128 | where ($($tnames: Clone,)* $($preds)*) 129 | ({ 130 | fn clone(&self) -> Self { 131 | match *self { 132 | $name($(ref $ford_ident),*) => $name($(Clone::clone($ford_ident)),*) 133 | } 134 | } 135 | }) 136 | } 137 | }; 138 | 139 | ( 140 | @item 141 | struct { 142 | attrs: $_attrs:tt, 143 | vis: $_vis:tt, 144 | name: $name:ident, 145 | generics: { 146 | constr: [$($constr:tt)*], 147 | params: [$($params:tt)*], 148 | ltimes: $_ltimes:tt, 149 | tnames: [$($tnames:ident,)*], 150 | }, 151 | where: { 152 | clause: $_clause:tt, 153 | preds: [$($preds:tt)*], 154 | }, 155 | kind: record, 156 | fields: [$( 157 | { 158 | ord: $_ford:tt, 159 | attrs: $_fattrs:tt, 160 | vis: $_fvis:tt, 161 | ty: $_fty:ty, 162 | name: $fname:ident, 163 | }, 164 | )*], 165 | $($_struct_tail:tt)* 166 | } 167 | ) => { 168 | Clone_mac! { 169 | @inject_where 170 | (impl<$($constr)*> Clone for $name<$($params)*>), 171 | where ($($tnames: Clone,)* $($preds)*) 172 | ({ 173 | fn clone(&self) -> Self { 174 | match *self { 175 | $name { $(ref $fname),* } => $name { $($fname: Clone::clone($fname)),* } 176 | } 177 | } 178 | }) 179 | } 180 | }; 181 | 182 | ( 183 | @var_match_pat 184 | $name:ident, 185 | { 186 | ord: $_ord:tt, 187 | attrs: $_attrs:tt, 188 | kind: unitary, 189 | name: $vname:ident, 190 | fields: [], 191 | num_fields: 0, 192 | } 193 | ) => { 194 | $name::$vname 195 | }; 196 | 197 | ( 198 | @var_match_body 199 | $name:ident, 200 | { 201 | ord: $_ord:tt, 202 | attrs: $_attrs:tt, 203 | kind: unitary, 204 | name: $vname:ident, 205 | fields: [], 206 | num_fields: 0, 207 | } 208 | ) => { 209 | $name::$vname 210 | }; 211 | 212 | ( 213 | @var_match_pat 214 | $name:ident, 215 | { 216 | ord: $_ord:tt, 217 | attrs: $_attrs:tt, 218 | kind: tuple, 219 | name: $vname:ident, 220 | fields: [ 221 | $( 222 | { 223 | ord: ($_ford:tt, $ford_ident:ident), 224 | attrs: $_fattrs:tt, 225 | vis: $_fvis:tt, 226 | ty: $_fty:ty, 227 | }, 228 | )+ 229 | ], 230 | num_fields: $_num_fields:tt, 231 | } 232 | ) => { 233 | $name::$vname($(ref $ford_ident,)+) 234 | }; 235 | 236 | ( 237 | @var_match_body 238 | $name:ident, 239 | { 240 | ord: $_ord:tt, 241 | attrs: $_attrs:tt, 242 | kind: tuple, 243 | name: $vname:ident, 244 | fields: [ 245 | $( 246 | { 247 | ord: ($_ford:tt, $ford_ident:ident), 248 | attrs: $_fattrs:tt, 249 | vis: $_fvis:tt, 250 | ty: $_fty:ty, 251 | }, 252 | )+ 253 | ], 254 | num_fields: $_num_fields:tt, 255 | } 256 | ) => { 257 | $name::$vname($(Clone::clone($ford_ident),)+) 258 | }; 259 | 260 | ( 261 | @var_match_pat 262 | $name:ident, 263 | { 264 | ord: $_ord:tt, 265 | attrs: $_attrs:tt, 266 | kind: record, 267 | name: $vname:ident, 268 | fields: [ 269 | $( 270 | { 271 | ord: $_ford:tt, 272 | attrs: $_fattrs:tt, 273 | vis: $_fvis:tt, 274 | ty: $_fty:ty, 275 | name: $fname:ident, 276 | }, 277 | )+ 278 | ], 279 | num_fields: $_num_fields:tt, 280 | } 281 | ) => { 282 | $name::$vname { $(ref $fname,)+ } 283 | }; 284 | 285 | ( 286 | @var_match_body 287 | $name:ident, 288 | { 289 | ord: $_ord:tt, 290 | attrs: $_attrs:tt, 291 | kind: record, 292 | name: $vname:ident, 293 | fields: [ 294 | $( 295 | { 296 | ord: $_ford:tt, 297 | attrs: $_fattrs:tt, 298 | vis: $_fvis:tt, 299 | ty: $_fty:ty, 300 | name: $fname:ident, 301 | }, 302 | )+ 303 | ], 304 | num_fields: $_num_fields:tt, 305 | } 306 | ) => { 307 | $name::$vname { $($fname: Clone::clone($fname),)+ } 308 | }; 309 | 310 | ( 311 | @inject_where 312 | ($($before:tt)*), 313 | where ($(,)*) 314 | ($($after:tt)*) 315 | ) => { 316 | Clone_mac! { 317 | @as_item 318 | $($before)* $($after)* 319 | } 320 | }; 321 | 322 | ( 323 | @inject_where 324 | ($($before:tt)*), 325 | where ($($preds:tt)+) 326 | ($($after:tt)*) 327 | ) => { 328 | Clone_mac! { 329 | @as_item 330 | $($before)* where $($preds)* $($after)* 331 | } 332 | }; 333 | 334 | (@as_item $i:item) => { $i }; 335 | } 336 | 337 | custom_derive! { 338 | #[derive(Clone_mac)] 339 | enum EnumA {} 340 | } 341 | 342 | custom_derive! { 343 | #[derive(Clone_mac)] 344 | enum EnumB { A } 345 | } 346 | 347 | custom_derive! { 348 | #[derive(Clone_mac)] 349 | enum EnumC { A, B, C } 350 | } 351 | 352 | custom_derive! { 353 | #[derive(Clone_mac)] 354 | enum EnumD { A, B(i32), C(u8, u8, u8) } 355 | } 356 | 357 | custom_derive! { 358 | #[derive(Clone_mac)] 359 | enum EnumE { A { r: u8, g: u8, b: u8, } } 360 | } 361 | 362 | custom_derive! { 363 | #[derive(Clone_mac)] 364 | enum EnumF { A { r: T, g: T, b: T, } } 365 | } 366 | 367 | custom_derive! { 368 | #[derive(Clone_mac)] 369 | struct StructA; 370 | } 371 | 372 | custom_derive! { 373 | #[derive(Clone_mac)] 374 | struct StructB(i32); 375 | } 376 | 377 | custom_derive! { 378 | #[derive(Clone_mac)] 379 | struct StructC(i32, u8, String); 380 | } 381 | 382 | custom_derive! { 383 | #[derive(Clone_mac)] 384 | struct StructD { 385 | /// The red stuff. 386 | r: u8, 387 | pub g: u8, 388 | b: u8, 389 | } 390 | } 391 | 392 | custom_derive! { 393 | #[derive(Copy, Clone_mac)] 394 | struct StructE { 395 | /// The red stuff. 396 | r: T, 397 | pub g: T, 398 | b: T, 399 | } 400 | } 401 | 402 | #[test] 403 | fn test_derive_clone() { 404 | if false { let _: EnumA = panic!(); } 405 | let _ = EnumB::A.clone(); 406 | let _ = EnumC::A.clone(); 407 | let _ = EnumC::B.clone(); 408 | let _ = EnumC::C.clone(); 409 | let _ = EnumD::A.clone(); 410 | let _ = EnumD::B(42).clone(); 411 | let _ = EnumD::C(1, 2, 3).clone(); 412 | let _ = (EnumE::A { r: 1, g: 2, b: 3 }).clone(); 413 | let _ = (EnumF::A { r: 1, g: 2, b: 3 }).clone(); 414 | let _ = StructA.clone(); 415 | let _ = StructB(42).clone(); 416 | let _ = StructC(42, 2, String::from("hi!")).clone(); 417 | let _ = (StructD { r: 1, g: 2, b: 3 }).clone(); 418 | } 419 | -------------------------------------------------------------------------------- /parse-macros/tests/derive_partial_ord.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg(channel="nightly")] 11 | #![feature(intrinsics)] 12 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 13 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 14 | #[macro_use] extern crate parse_generics_shim; 15 | 16 | #[macro_use] extern crate custom_derive; 17 | #[macro_use] extern crate parse_macros; 18 | 19 | use std::cmp::Ordering; 20 | 21 | extern "rust-intrinsic" { 22 | pub fn discriminant_value(v: &T) -> u64; 23 | } 24 | 25 | macro_rules! PartialOrd_mac { 26 | ( 27 | () $($tail:tt)* 28 | ) => { 29 | parse_item! { 30 | then PartialOrd_mac! { @item }, 31 | $($tail)* 32 | } 33 | }; 34 | 35 | ( 36 | @item 37 | enum { 38 | attrs: $_attrs:tt, 39 | vis: $_vis:tt, 40 | name: $name:ident, 41 | generics: { 42 | constr: [$($constr:tt)*], 43 | params: [$($params:tt)*], 44 | ltimes: $_ltimes:tt, 45 | tnames: [$($tnames:ident,)*], 46 | }, 47 | where: { 48 | clause: $_clause:tt, 49 | preds: [$($preds:tt)*], 50 | }, 51 | variants: [], 52 | $($_enum_tail:tt)* 53 | } 54 | ) => { 55 | PartialOrd_mac! { 56 | @inject_where 57 | (impl<$($constr)*> PartialOrd for $name<$($params)*>), 58 | where ($($tnames: PartialOrd,)* $($preds)*) 59 | ({ 60 | fn partial_cmp(&self, _: &Self) -> Option { 61 | Some(Ordering::Equal) 62 | } 63 | }) 64 | } 65 | }; 66 | 67 | ( 68 | @item 69 | enum { 70 | attrs: $_attrs:tt, 71 | vis: $_vis:tt, 72 | name: $name:ident, 73 | generics: { 74 | constr: [$($constr:tt)*], 75 | params: [$($params:tt)*], 76 | ltimes: $_ltimes:tt, 77 | tnames: [$($tnames:ident,)*], 78 | }, 79 | where: { 80 | clause: $_clause:tt, 81 | preds: [$($preds:tt)*], 82 | }, 83 | variants: [$var:tt,], 84 | $($_enum_tail:tt)* 85 | } 86 | ) => { 87 | PartialOrd_mac! { 88 | @inject_where 89 | (impl<$($constr)*> PartialOrd for $name<$($params)*>), 90 | where ($($tnames: PartialOrd,)* $($preds)*) 91 | ({ 92 | fn partial_cmp(&self, other: &Self) -> Option { 93 | match (self, other) { 94 | PartialOrd_mac!(@var_match_pat other, $name, $var) => PartialOrd_mac!(@var_match_body other, $name, $var), 95 | } 96 | } 97 | }) 98 | } 99 | }; 100 | 101 | ( 102 | @item 103 | enum { 104 | attrs: $_attrs:tt, 105 | vis: $_vis:tt, 106 | name: $name:ident, 107 | generics: { 108 | constr: [$($constr:tt)*], 109 | params: [$($params:tt)*], 110 | ltimes: $_ltimes:tt, 111 | tnames: [$($tnames:ident,)*], 112 | }, 113 | where: { 114 | clause: $_clause:tt, 115 | preds: [$($preds:tt)*], 116 | }, 117 | variants: [$($vars:tt,)*], 118 | $($_enum_tail:tt)* 119 | } 120 | ) => { 121 | PartialOrd_mac! { 122 | @inject_where 123 | (impl<$($constr)*> PartialOrd for $name<$($params)*>), 124 | where ($($tnames: PartialOrd,)* $($preds)*) 125 | ({ 126 | fn partial_cmp(&self, other: &Self) -> Option { 127 | let sd = unsafe { discriminant_value(self) }; 128 | let od = unsafe { discriminant_value(other) }; 129 | 130 | if sd != od { 131 | return sd.partial_cmp(&od); 132 | } 133 | 134 | match (self, other) { 135 | $( 136 | PartialOrd_mac!(@var_match_pat other, $name, $vars) => PartialOrd_mac!(@var_match_body other, $name, $vars), 137 | )* 138 | _ => unreachable!() 139 | } 140 | } 141 | }) 142 | } 143 | }; 144 | 145 | ( 146 | @item 147 | struct { 148 | attrs: $_attrs:tt, 149 | vis: $_vis:tt, 150 | name: $name:ident, 151 | generics: { 152 | constr: [$($constr:tt)*], 153 | params: [$($params:tt)*], 154 | ltimes: $_ltimes:tt, 155 | tnames: [$($tnames:ident,)*], 156 | }, 157 | where: { 158 | clause: $_clause:tt, 159 | preds: [$($preds:tt)*], 160 | }, 161 | kind: unitary, 162 | fields: [], 163 | $($_struct_tail:tt)* 164 | } 165 | ) => { 166 | PartialOrd_mac! { 167 | @inject_where 168 | (impl<$($constr)*> PartialOrd for $name<$($params)*>), 169 | where ($($tnames: PartialOrd,)* $($preds)*) 170 | ({ 171 | fn partial_cmp(&self, _: &Self) -> Option { 172 | Some(Ordering::Equal) 173 | } 174 | }) 175 | } 176 | }; 177 | 178 | ( 179 | @item 180 | struct { 181 | attrs: $_attrs:tt, 182 | vis: $_vis:tt, 183 | name: $name:ident, 184 | generics: { 185 | constr: [$($constr:tt)*], 186 | params: [$($params:tt)*], 187 | ltimes: $_ltimes:tt, 188 | tnames: [$($tnames:ident,)*], 189 | }, 190 | where: { 191 | clause: $_clause:tt, 192 | preds: [$($preds:tt)*], 193 | }, 194 | kind: tuple, 195 | fields: [$( 196 | { 197 | ord: ($ford:tt, $_ford_ident:ident), 198 | attrs: $_fattrs:tt, 199 | vis: $_fvis:tt, 200 | ty: $_fty:ty, 201 | }, 202 | )*], 203 | $($_struct_tail:tt)* 204 | } 205 | ) => { 206 | PartialOrd_mac! { 207 | @inject_where 208 | (impl<$($constr)*> PartialOrd for $name<$($params)*>), 209 | where ($($tnames: PartialOrd,)* $($preds)*) 210 | ({ 211 | fn partial_cmp(&self, other: &Self) -> Option { 212 | $( 213 | PartialOrd_mac!(@as_expr 214 | match (self.$ford).partial_cmp(&other.$ford) { 215 | Some(Ordering::Equal) => (), 216 | other => return other 217 | } 218 | ); 219 | )* 220 | Some(Ordering::Equal) 221 | } 222 | }) 223 | } 224 | }; 225 | 226 | ( 227 | @item 228 | struct { 229 | attrs: $_attrs:tt, 230 | vis: $_vis:tt, 231 | name: $name:ident, 232 | generics: { 233 | constr: [$($constr:tt)*], 234 | params: [$($params:tt)*], 235 | ltimes: $_ltimes:tt, 236 | tnames: [$($tnames:ident,)*], 237 | }, 238 | where: { 239 | clause: $_clause:tt, 240 | preds: [$($preds:tt)*], 241 | }, 242 | kind: record, 243 | fields: [$( 244 | { 245 | ord: $_ford:tt, 246 | attrs: $_fattrs:tt, 247 | vis: $_fvis:tt, 248 | ty: $_fty:ty, 249 | name: $fname:ident, 250 | }, 251 | )*], 252 | $($_struct_tail:tt)* 253 | } 254 | ) => { 255 | PartialOrd_mac! { 256 | @inject_where 257 | (impl<$($constr)*> PartialOrd for $name<$($params)*>), 258 | where ($($tnames: PartialOrd,)* $($preds)*) 259 | ({ 260 | fn partial_cmp(&self, other: &Self) -> Option { 261 | $( 262 | match self.$fname.partial_cmp(&other.$fname) { 263 | Some(Ordering::Equal) => (), 264 | other => return other 265 | } 266 | )* 267 | Some(Ordering::Equal) 268 | } 269 | }) 270 | } 271 | }; 272 | 273 | ( 274 | @var_match_pat 275 | $_other:ident, 276 | $name:ident, 277 | { 278 | ord: $_ord:tt, 279 | attrs: $_attrs:tt, 280 | kind: unitary, 281 | name: $vname:ident, 282 | fields: [], 283 | num_fields: 0, 284 | } 285 | ) => { 286 | (&$name::$vname, &$name::$vname) 287 | }; 288 | 289 | ( 290 | @var_match_body 291 | $_other:ident, 292 | $name:ident, 293 | { 294 | ord: $_ord:tt, 295 | attrs: $_attrs:tt, 296 | kind: unitary, 297 | name: $vname:ident, 298 | fields: [], 299 | num_fields: 0, 300 | } 301 | ) => { 302 | Some(Ordering::Equal) 303 | }; 304 | 305 | ( 306 | @var_match_pat 307 | $other:ident, 308 | $name:ident, 309 | { 310 | ord: $_ord:tt, 311 | attrs: $_attrs:tt, 312 | kind: tuple, 313 | name: $vname:ident, 314 | fields: [ 315 | $( 316 | { 317 | ord: ($_ford:tt, $ford_ident:ident), 318 | attrs: $_fattrs:tt, 319 | vis: $_fvis:tt, 320 | ty: $_fty:ty, 321 | }, 322 | )+ 323 | ], 324 | num_fields: $_num_fields:tt, 325 | } 326 | ) => { 327 | (&$name::$vname($(ref $ford_ident,)+), $other) 328 | }; 329 | 330 | ( 331 | @var_match_body 332 | $other:ident, 333 | $name:ident, 334 | { 335 | ord: $_ord:tt, 336 | attrs: $_attrs:tt, 337 | kind: tuple, 338 | name: $vname:ident, 339 | fields: [ 340 | $( 341 | { 342 | ord: ($ford:tt, $ford_ident:ident), 343 | attrs: $_fattrs:tt, 344 | vis: $_fvis:tt, 345 | ty: $_fty:ty, 346 | }, 347 | )+ 348 | ], 349 | num_fields: $_num_fields:tt, 350 | } 351 | ) => { 352 | { 353 | let lhs = ($($ford_ident,)+); 354 | match $other { 355 | &$name::$vname($(ref $ford_ident,)+) => { 356 | let rhs = ($($ford_ident,)+); 357 | $( 358 | match PartialOrd_mac!(@as_expr (lhs.$ford).partial_cmp(&rhs.$ford)) { 359 | Some(Ordering::Equal) => (), 360 | other => return other 361 | } 362 | )+ 363 | Some(Ordering::Equal) 364 | }, 365 | _ => unreachable!() 366 | } 367 | } 368 | }; 369 | 370 | ( 371 | @var_match_pat 372 | $_other:ident, 373 | $name:ident, 374 | { 375 | ord: $_ord:tt, 376 | attrs: $_attrs:tt, 377 | kind: record, 378 | name: $vname:ident, 379 | fields: [ 380 | $( 381 | { 382 | ord: ($_ford:tt, $ford_ident:ident), 383 | attrs: $_fattrs:tt, 384 | vis: $_fvis:tt, 385 | ty: $_fty:ty, 386 | name: $fname:ident, 387 | }, 388 | )+ 389 | ], 390 | num_fields: $_num_fields:tt, 391 | } 392 | ) => { 393 | (&$name::$vname { $(ref $fname,)+ }, 394 | &$name::$vname { $($fname: ref $ford_ident,)+ }) 395 | }; 396 | 397 | ( 398 | @var_match_body 399 | $_other:ident, 400 | $name:ident, 401 | { 402 | ord: $_ord:tt, 403 | attrs: $_attrs:tt, 404 | kind: record, 405 | name: $vname:ident, 406 | fields: [ 407 | $( 408 | { 409 | ord: ($_ford:tt, $ford_ident:ident), 410 | attrs: $_fattrs:tt, 411 | vis: $_fvis:tt, 412 | ty: $_fty:ty, 413 | name: $fname:ident, 414 | }, 415 | )+ 416 | ], 417 | num_fields: $_num_fields:tt, 418 | } 419 | ) => { 420 | { 421 | $( 422 | match $fname.partial_cmp(&$ford_ident) { 423 | Some(Ordering::Equal) => (), 424 | other => return other 425 | } 426 | )+ 427 | Some(Ordering::Equal) 428 | } 429 | }; 430 | 431 | ( 432 | @inject_where 433 | ($($before:tt)*), 434 | where ($(,)*) 435 | ($($after:tt)*) 436 | ) => { 437 | PartialOrd_mac! { 438 | @as_item 439 | $($before)* $($after)* 440 | } 441 | }; 442 | 443 | ( 444 | @inject_where 445 | ($($before:tt)*), 446 | where ($($preds:tt)+) 447 | ($($after:tt)*) 448 | ) => { 449 | PartialOrd_mac! { 450 | @as_item 451 | $($before)* where $($preds)* $($after)* 452 | } 453 | }; 454 | 455 | (@as_expr $e:expr) => { $e }; 456 | (@as_item $i:item) => { $i }; 457 | } 458 | 459 | custom_derive! { 460 | #[derive(PartialEq, PartialOrd_mac)] 461 | enum EnumA {} 462 | } 463 | 464 | custom_derive! { 465 | #[derive(PartialEq, PartialOrd_mac)] 466 | enum EnumB { A } 467 | } 468 | 469 | custom_derive! { 470 | #[derive(PartialEq, PartialOrd_mac)] 471 | enum EnumC { A, B, C } 472 | } 473 | 474 | custom_derive! { 475 | #[derive(PartialEq, PartialOrd_mac)] 476 | enum EnumD { A, B(i32), C(u8, u8, u8) } 477 | } 478 | 479 | custom_derive! { 480 | #[derive(PartialEq, PartialOrd_mac)] 481 | enum EnumE { A { r: u8, g: u8, b: u8, } } 482 | } 483 | 484 | custom_derive! { 485 | #[derive(PartialEq, PartialOrd_mac)] 486 | enum EnumF { A { r: T, g: T, b: T, } } 487 | } 488 | 489 | custom_derive! { 490 | #[derive(PartialEq, PartialOrd_mac)] 491 | struct StructA; 492 | } 493 | 494 | custom_derive! { 495 | #[derive(PartialEq, PartialOrd_mac)] 496 | struct StructB(i32); 497 | } 498 | 499 | custom_derive! { 500 | #[derive(PartialEq, PartialOrd_mac)] 501 | struct StructC(i32, u8, String); 502 | } 503 | 504 | custom_derive! { 505 | #[derive(PartialEq, PartialOrd_mac)] 506 | struct StructD { 507 | /// The red stuff. 508 | r: u8, 509 | pub g: u8, 510 | b: u8, 511 | } 512 | } 513 | 514 | custom_derive! { 515 | #[derive(Clone, PartialEq, PartialOrd_mac)] 516 | struct StructE { 517 | /// The red stuff. 518 | r: T, 519 | pub g: T, 520 | b: T, 521 | } 522 | } 523 | 524 | #[test] 525 | fn test_partial_ord() { 526 | if false { let _x: EnumA = panic!(); _x.partial_cmp(&_x); } 527 | { let x = EnumB::A; x.partial_cmp(&x); } 528 | { let x = EnumC::A; x.partial_cmp(&x); } 529 | { let x = EnumC::B; x.partial_cmp(&x); } 530 | { let x = EnumC::C; x.partial_cmp(&x); } 531 | { let x = EnumD::A; x.partial_cmp(&x); } 532 | { let x = EnumD::B(42); x.partial_cmp(&x); } 533 | { let x = EnumD::C(1, 2, 3); x.partial_cmp(&x); } 534 | { let x = EnumE::A { r: 1, g: 2, b: 3 }; x.partial_cmp(&x); } 535 | { let x = EnumF::A { r: 1, g: 2, b: 3 }; x.partial_cmp(&x); } 536 | { let x = StructA; x.partial_cmp(&x); } 537 | { let x = StructB(42); x.partial_cmp(&x); } 538 | { let x = StructC(42, 2, String::from("hi!")); x.partial_cmp(&x); } 539 | { let x = StructD { r: 1, g: 2, b: 3 }; x.partial_cmp(&x); } 540 | { let x = StructE { r: 1, g: 2, b: 3 }; x.partial_cmp(&x); } 541 | } 542 | -------------------------------------------------------------------------------- /parse-macros/tests/reflect.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 11 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 12 | #[macro_use] extern crate parse_generics_shim; 13 | 14 | #[macro_use] extern crate custom_derive; 15 | #[macro_use] extern crate parse_macros; 16 | 17 | macro_rules! Reflect { 18 | (() $($tail:tt)*) => { 19 | parse_item! { 20 | then Reflect! { @item }, 21 | $($tail)* 22 | } 23 | }; 24 | 25 | (@as_item $i:item) => { $i }; 26 | 27 | ( 28 | @item 29 | struct { 30 | attrs: $_attrs:tt, 31 | vis: $vis:tt, 32 | name: $name:ident, 33 | generics: { 34 | constr: [ $($constr:tt)* ], 35 | params: [ $($params:tt)* ], 36 | ltimes: [ $($ltimes:tt,)* ], 37 | tnames: [ $($tnames:ident,)* ], 38 | }, 39 | where: { 40 | clause: $_clause:tt, 41 | preds: [ $($preds:tt)* ], 42 | }, 43 | kind: $_kind:tt, 44 | fields: $fields:tt, 45 | $($_tail:tt)* 46 | } 47 | ) => { 48 | Reflect! { 49 | @as_item 50 | impl<$($constr)*> Reflect for $name<$($params)*> 51 | where $($tnames: Reflect,)* $($preds)* { 52 | fn reflect() -> Type { 53 | let fields = Reflect!(@record_fields $fields); 54 | let item = Item { 55 | visibility: vis_to_visibility!($vis), 56 | module: module_path!(), 57 | name: stringify!($name), 58 | kind: ItemKind::Struct(Struct { 59 | fields: fields, 60 | }), 61 | }; 62 | Type::Item(item) 63 | } 64 | } 65 | } 66 | }; 67 | 68 | ( 69 | @record_fields 70 | [ 71 | $( 72 | { 73 | ord: $_ord:tt, 74 | attrs: $_attrs:tt, 75 | vis: $vis:tt, 76 | ty: $ty:ty, 77 | name: $name:ident, 78 | $(_field_tail:tt)* 79 | }, 80 | )* 81 | ] 82 | ) => { 83 | vec![ 84 | $( 85 | RecordField { 86 | visibility: vis_to_visibility!($vis), 87 | name: stringify!($name), 88 | ty: Box::new(<$ty as Reflect>::reflect()), 89 | }, 90 | )* 91 | ].into_boxed_slice() 92 | }; 93 | } 94 | 95 | macro_rules! vis_to_visibility { 96 | (()) => { Visibility::Private }; 97 | ((pub)) => { Visibility::Public }; 98 | } 99 | 100 | pub trait Reflect { 101 | fn reflect() -> Type; 102 | } 103 | 104 | impl Reflect for u8 { 105 | fn reflect() -> Type { 106 | Type::Lang(Lang::U8) 107 | } 108 | } 109 | 110 | impl Reflect for Option 111 | where T: Reflect { 112 | fn reflect() -> Type { 113 | Type::Item(Item { 114 | visibility: Visibility::Public, 115 | module: "core::option", 116 | name: "Option", 117 | kind: ItemKind::Enum(Enum { 118 | variants: vec![ 119 | EnumVariant { 120 | name: "None", 121 | kind: EnumVariantKind::Unitary, 122 | }, 123 | EnumVariant { 124 | name: "Some", 125 | kind: EnumVariantKind::Tuple(vec![ 126 | TupleField { 127 | ty: Box::new(::reflect()), 128 | }, 129 | ].into_boxed_slice()), 130 | }, 131 | ].into_boxed_slice(), 132 | }), 133 | }) 134 | } 135 | } 136 | 137 | #[derive(Debug)] 138 | pub enum Type { 139 | Lang(Lang), 140 | Item(Item), 141 | } 142 | 143 | #[derive(Debug)] 144 | pub enum Lang { 145 | U8, 146 | } 147 | 148 | #[derive(Debug)] 149 | pub struct Item { 150 | pub visibility: Visibility, 151 | pub module: &'static str, 152 | pub name: &'static str, 153 | pub kind: ItemKind, 154 | } 155 | 156 | #[derive(Debug)] 157 | pub enum ItemKind { 158 | Enum(Enum), 159 | Struct(Struct), 160 | } 161 | 162 | #[derive(Debug)] 163 | pub struct Enum { 164 | pub variants: Box<[EnumVariant]>, 165 | } 166 | 167 | #[derive(Debug)] 168 | pub struct EnumVariant { 169 | pub name: &'static str, 170 | pub kind: EnumVariantKind, 171 | } 172 | 173 | #[derive(Debug)] 174 | pub enum EnumVariantKind { 175 | Unitary, 176 | Tuple(Box<[TupleField]>), 177 | Record(Box<[RecordField]>), 178 | } 179 | 180 | #[derive(Debug)] 181 | pub struct Struct { 182 | pub fields: Box<[RecordField]>, 183 | } 184 | 185 | #[derive(Debug)] 186 | pub enum Visibility { Private, Public } 187 | 188 | #[derive(Debug)] 189 | pub struct TupleField { 190 | pub ty: Box, 191 | } 192 | 193 | #[derive(Debug)] 194 | pub struct RecordField { 195 | pub visibility: Visibility, 196 | pub name: &'static str, 197 | pub ty: Box, 198 | } 199 | 200 | custom_derive! { 201 | #[derive(Debug)] 202 | #[derive(Reflect)] 203 | struct Rgba where T: Copy { 204 | /// The red stuff 205 | r: T, 206 | #[doc="delicious green flavour"] 207 | g: T, 208 | pub b: T, 209 | /// Maybe alpha, maybe not. 210 | pub a: Option, 211 | } 212 | } 213 | 214 | macro_rules! aeqiws { 215 | ($lhs:expr, $rhs:expr) => { 216 | { 217 | let lhs = $lhs.replace(char::is_whitespace, ""); 218 | let rhs = $rhs.replace(char::is_whitespace, ""); 219 | if lhs != rhs { 220 | panic!("assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`)", lhs, rhs); 221 | } 222 | } 223 | }; 224 | } 225 | 226 | #[test] 227 | fn test_reflect() { 228 | aeqiws!( 229 | format!("{:?}", Rgba::::reflect()), 230 | r#" 231 | Item(Item { 232 | visibility: Private, 233 | module: "reflect", 234 | name: "Rgba", 235 | kind: Struct(Struct { 236 | fields: [ 237 | RecordField { 238 | visibility: Private, 239 | name: "r", 240 | ty: Lang(U8) 241 | }, 242 | RecordField { 243 | visibility: Private, 244 | name: "g", 245 | ty: Lang(U8) 246 | }, 247 | RecordField { 248 | visibility: Public, 249 | name: "b", 250 | ty: Lang(U8) 251 | }, 252 | RecordField { 253 | visibility: Public, 254 | name: "a", 255 | ty: Item(Item { 256 | visibility: Public, 257 | module: "core::option", 258 | name: "Option", 259 | kind: Enum(Enum { 260 | variants: [ 261 | EnumVariant { 262 | name: "None", 263 | kind: Unitary 264 | }, 265 | EnumVariant { 266 | name: "Some", 267 | kind: Tuple([ 268 | TupleField { 269 | ty: Lang(U8) 270 | } 271 | ]) 272 | } 273 | ] 274 | }) 275 | }) 276 | } 277 | ] 278 | }) 279 | }) 280 | "# 281 | ); 282 | } 283 | -------------------------------------------------------------------------------- /parse-macros/tests/simple.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ⓒ 2016 rust-custom-derive contributors. 3 | 4 | Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 6 | ), at your option. All 7 | files in the project carrying such notice may not be copied, modified, 8 | or distributed except according to those terms. 9 | */ 10 | #![cfg_attr(feature="parse-generics-poc", feature(plugin))] 11 | #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))] 12 | #[macro_use] extern crate parse_generics_shim; 13 | 14 | #[macro_use] extern crate custom_derive; 15 | #[macro_use] extern crate parse_macros; 16 | 17 | macro_rules! aeqiws { 18 | ($lhs:expr, $rhs:expr) => { 19 | { 20 | let lhs = $lhs.replace(char::is_whitespace, ""); 21 | let rhs = $rhs.replace(char::is_whitespace, ""); 22 | if lhs != rhs { 23 | panic!("assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`)", lhs, rhs); 24 | } 25 | } 26 | }; 27 | } 28 | 29 | #[test] 30 | fn test_simple_type_item() { 31 | aeqiws!( 32 | parse_item!( 33 | then stringify!(), 34 | #[doc(hidden)] type Result = ::std::result::Result; 35 | ), 36 | r#" 37 | type { 38 | attrs: [ #[doc(hidden)] ], 39 | vis: (), 40 | name: Result, 41 | generics: { 42 | constr: [T,], 43 | params: [T,], 44 | ltimes: [], 45 | tnames: [T,], 46 | }, 47 | where: { 48 | preds: [], 49 | }, 50 | type: ::std::result::Result, 51 | } 52 | "# 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /scripts/update-docs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | 4 | # Copyright ⓒ 2016 Daniel Keep. 5 | # 6 | # Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of 8 | # ), at your option. All 9 | # files in the project carrying such notice may not be copied, modified, 10 | # or distributed except according to those terms. 11 | 12 | import distutils.dir_util 13 | import os 14 | import shutil 15 | import subprocess 16 | import sys 17 | import tempfile 18 | import time 19 | 20 | from itertools import chain 21 | 22 | DOC_ARGS = '--no-deps' 23 | DOC_FEATURES = "" 24 | DOC_TARGET_BRANCH = 'gh-pages' 25 | DOC_PKG_DIR = 'doc-pkg' 26 | DOC_TOOLCHAIN = "nightly-2016-04-06" 27 | TEMP_CHECKOUT_PREFIX = 'gh-pages-checkout-' 28 | TEMP_OUTPUT_PREFIX = 'gh-pages-generated-' 29 | 30 | USE_ANSI = True if sys.platform != 'win32' else os.environ.get('FORCE_ANSI', '') != '' 31 | TRACE_UPDATE_DOCS = os.environ.get('TRACE_UPDATE_DOCS', '') != '' 32 | 33 | def which(programname, all=False): 34 | path_exts = os.environ.get('PATHEXT', '').split(os.path.pathsep) 35 | path_exts = [e for e in path_exts if e.lstrip() != ''] 36 | 37 | def matches(): 38 | for path in os.environ['PATH'].split(os.path.pathsep): 39 | base_path = os.path.join(path, programname) 40 | for ext in chain(('',), path_exts): 41 | ext_path = base_path+ext 42 | if os.path.exists(os.path.normcase(ext_path)): 43 | yield ext_path 44 | 45 | if all: 46 | return matches() 47 | else: 48 | return next(matches(), None) 49 | 50 | RUSTUP = "rustup" if which("rustup") is not None else "multirust" 51 | 52 | def sh(cmd): 53 | msg_trace('sh(%r)' % cmd) 54 | try: 55 | subprocess.check_call(cmd, shell=True) 56 | except: 57 | msg_trace('FAILED!') 58 | raise 59 | 60 | def sh_eval(cmd, codec='utf-8', dont_strip=False): 61 | msg_trace('sh_eval(%r)' % cmd) 62 | result = None 63 | try: 64 | result = subprocess.check_output(cmd, shell=True).decode(codec) 65 | if not dont_strip: 66 | result = result.strip() 67 | except: 68 | msg_trace('FAILED!') 69 | raise 70 | return result 71 | 72 | def msg(*args): 73 | if USE_ANSI: sys.stdout.write('\x1b[1;34m') 74 | sys.stdout.write('> ') 75 | if USE_ANSI: sys.stdout.write('\x1b[1;32m') 76 | for arg in args: 77 | sys.stdout.write(str(arg)) 78 | if USE_ANSI: sys.stdout.write('\x1b[0m') 79 | sys.stdout.write('\n') 80 | sys.stdout.flush() 81 | 82 | def msg_trace(*args): 83 | if TRACE_UPDATE_DOCS: 84 | if USE_ANSI: sys.stderr.write('\x1b[1;31m') 85 | sys.stderr.write('$ ') 86 | if USE_ANSI: sys.stderr.write('\x1b[0m') 87 | for arg in args: 88 | sys.stderr.write(str(arg)) 89 | sys.stderr.write('\n') 90 | sys.stderr.flush() 91 | 92 | def copytree(src, dst): 93 | msg_trace('copytree(%r, %r)' % (src, dst)) 94 | distutils.dir_util.copy_tree(src=src, dst=dst) 95 | 96 | def really_rmtree(path): 97 | msg_trace('really_rmtree(%r)' % path) 98 | 99 | WAIT_TIME_SECS = 1.0 100 | MAX_TRIES = 10 101 | 102 | def on_error(func, path, exc_info): 103 | """ 104 | Error handler for ``shutil.rmtree``. 105 | 106 | If the error is due to an access error (read only file) 107 | it attempts to add write permission and then retries. 108 | 109 | If the error is for another reason it re-raises the error. 110 | 111 | Usage: ``shutil.rmtree(path, onerror=on_error)`` 112 | 113 | From _. 114 | """ 115 | import stat 116 | if not os.access(path, os.W_OK): 117 | # Is the error an access error ? 118 | os.chmod(path, stat.S_IWUSR) 119 | func(path) 120 | else: 121 | raise 122 | 123 | for _ in range(MAX_TRIES): 124 | failed = True 125 | try: 126 | msg_trace('shutil.rmtree(%r)' % path) 127 | shutil.rmtree(path, onerror=on_error) 128 | failed = False 129 | except WindowsError: 130 | time.sleep(WAIT_TIME_SECS) 131 | if not failed: return 132 | 133 | msg('Warning: failed to remove directory %r' % path) 134 | 135 | def init_doc_branch(): 136 | msg("Initialising %s branch" % DOC_TARGET_BRANCH) 137 | 138 | dir = os.getcwd() 139 | msg_trace('dir = %r' % dir) 140 | 141 | tmp = tempfile.mkdtemp(prefix=TEMP_CHECKOUT_PREFIX) 142 | msg_trace('tmp = %r' % tmp) 143 | 144 | try: 145 | msg("Cloning into a temporary directory...") 146 | sh('git init -q "%s"' % tmp) 147 | msg_trace('os.chdir(%r)' % tmp) 148 | os.chdir(tmp) 149 | sh('git checkout -q --orphan "%s"' % DOC_TARGET_BRANCH) 150 | sh('git commit -qm "Initial commit." --allow-empty') 151 | sh('git remote add origin "%s"' % dir) 152 | sh('git push -q origin gh-pages') 153 | 154 | finally: 155 | msg('Cleaning up...') 156 | msg_trace('os.chdir(%r)' % dir) 157 | os.chdir(dir) 158 | msg_trace('shutil.rmtree(%r)' % tmp) 159 | really_rmtree(tmp) 160 | 161 | msg('%s is ready. Continuing.' % DOC_TARGET_BRANCH) 162 | 163 | def gen_doc_bare(tmp1, tmp2): 164 | msg("Generating documentation...") 165 | args = '%s --features="%s"' % (DOC_ARGS, DOC_FEATURES) 166 | if DOC_TOOLCHAIN is not None: 167 | toolchain = "%s run %s " % (RUSTUP, DOC_TOOLCHAIN) 168 | else: 169 | toolchain = "" 170 | sh('%scargo doc %s' % (toolchain, args)) 171 | tmp1_target_doc = '%s/target/doc' % tmp1 172 | msg_trace('shutil.move(%r, %r)' % (tmp1_target_doc, tmp2)) 173 | shutil.move(tmp1_target_doc, tmp2) 174 | 175 | def gen_doc_pkg(tmp1, tmp2, doc_pkg): 176 | if DOC_FEATURES != "": 177 | msg("Error: doc packages don't support features.") 178 | sys.exit(1) 179 | 180 | import json 181 | old_dir = os.getcwd() 182 | msg("Generating documentation from doc package...") 183 | msg_trace('doc_pkg = %r' % doc_pkg) 184 | msg_trace('os.chdir(%r)' % doc_pkg) 185 | try: 186 | os.chdir(doc_pkg) 187 | manifest_str = sh_eval('cargo read-manifest --manifest-path "%s"' 188 | % os.path.join(doc_pkg, 'Cargo.toml')) 189 | manifest = json.loads(manifest_str) 190 | if DOC_TOOLCHAIN is not None: 191 | toolchain = "%s run %s " % (RUSTUP, DOC_TOOLCHAIN) 192 | else: 193 | toolchain = "" 194 | packages = " ".join("--package %s" % d['name'] for d in manifest['dependencies']) 195 | sh('%scargo doc %s' % (toolchain, packages)) 196 | target_doc = os.path.join(doc_pkg, 'target/doc') 197 | msg_trace('shutil.move(%r, %r)' % (target_doc, tmp2)) 198 | shutil.move(target_doc, tmp2) 199 | finally: 200 | msg_trace('os.chdir(%r)' % old_dir) 201 | os.chdir(old_dir) 202 | 203 | def main(): 204 | if sh_eval('git symbolic-ref --short HEAD') != u'master': 205 | msg('Not on master; doing nothing.') 206 | return 0 207 | 208 | # Sanity check: does the doc branch exist at all? 209 | branches = {b[2:].strip() for b in sh_eval('git branch', dont_strip=True).splitlines()} 210 | msg_trace('branches = %r' % branches) 211 | if DOC_TARGET_BRANCH not in branches: 212 | init_doc_branch() 213 | 214 | last_rev = sh_eval('git rev-parse HEAD') 215 | last_msg = sh_eval('git log -1 --pretty=%B') 216 | msg_trace('last_rev = %r' % last_rev) 217 | msg_trace('last_msg = %r' % last_msg) 218 | 219 | dir = os.getcwd() 220 | msg_trace('dir = %r' % dir) 221 | 222 | tmp1 = tempfile.mkdtemp(prefix=TEMP_CHECKOUT_PREFIX) 223 | tmp2 = tempfile.mkdtemp(prefix=TEMP_OUTPUT_PREFIX) 224 | msg_trace('tmp1 = %r' % tmp1) 225 | msg_trace('tmp2 = %r' % tmp2) 226 | 227 | try: 228 | msg("Cloning into a temporary directory...") 229 | sh('git clone -qb "%s" "%s" "%s"' % (DOC_TARGET_BRANCH, dir, tmp1)) 230 | msg_trace('os.chdir(%r)' % tmp1) 231 | os.chdir(tmp1) 232 | sh('git checkout -q master') 233 | 234 | if DOC_PKG_DIR is not None: 235 | gen_doc_pkg(tmp1, tmp2, os.path.abspath(DOC_PKG_DIR)) 236 | else: 237 | gen_doc_bare(tmp1, tmp2) 238 | 239 | msg('Updating %s...' % DOC_TARGET_BRANCH) 240 | sh('git checkout -q "%s"' % DOC_TARGET_BRANCH) 241 | sh('git clean -dfq') 242 | tmp2_doc = '%s/doc' % tmp2 243 | 244 | msg_trace('copytree(%r, %r)' % (tmp2_doc, './doc')) 245 | copytree(tmp2_doc, './doc') 246 | 247 | msg('Committing changes...') 248 | sh('git add .') 249 | sh('git commit --amend -m "Update docs for %s" -m "%s"' % (last_rev[:7], last_msg)) 250 | 251 | sh('git push -fqu origin "%s"' % DOC_TARGET_BRANCH) 252 | 253 | finally: 254 | msg('Cleaning up...') 255 | msg_trace('os.chdir(%r)' % dir) 256 | os.chdir(dir) 257 | msg_trace('shutil.rmtree(%r)' % tmp2) 258 | really_rmtree(tmp2) 259 | msg_trace('shutil.rmtree(%r)' % tmp1) 260 | really_rmtree(tmp1) 261 | 262 | msg('Publishing...') 263 | sh('git push -f origin "%s"' % DOC_TARGET_BRANCH) 264 | 265 | msg('Done.') 266 | 267 | 268 | if __name__ == '__main__': 269 | sys.exit(main()) 270 | --------------------------------------------------------------------------------