diff --git a/Cargo.lock b/Cargo.lock index 0742039..7e1259d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,18 +94,18 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array", ] [[package]] name = "bumpalo" -version = "3.11.0" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "cbor_event" @@ -113,10 +113,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52b3d8b289b6c7d6d8832c8e2bf151c7677126afa627f51e19a6320aec8237cb" +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cddl" -version = "0.9.0" -source = "git+https://github.com/anweiss/cddl?branch=dcSpark-ast-parent-pointer#a94078e041023052c6c8d4b8786c6267a0696c1a" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "286a21bdd91f4cab45c26ae7310f73aedf1e8f6fe21e210d220c449991c7fcf4" dependencies = [ "abnf_to_pest", "base16", @@ -282,9 +289,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -324,11 +331,55 @@ dependencies = [ "typenum", ] +[[package]] +name = "cxx" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f83d0ebf42c6eafb8d7c52f7e5f2d3003b89c7aa4fd2b79229209459a849af8" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07d050484b55975889284352b0ffc2ecbda25c0c55978017c132b29ba0818a86" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d2199b00553eda8012dfec8d3b1c75fce747cf27c169a270b3b99e3448ab78" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb67a6de1f602736dd7eaead0080cf3435df806c61b24b13328db128c58868f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ "block-buffer", "crypto-common", @@ -402,18 +453,28 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "iana-time-zone" -version = "0.1.47" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" +checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" dependencies = [ "android_system_properties", "core-foundation-sys", + "iana-time-zone-haiku", "js-sys", - "once_cell", "wasm-bindgen", "winapi", ] +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "indexmap" version = "1.9.1" @@ -426,24 +487,24 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -524,11 +585,20 @@ version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "lock_api" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -564,7 +634,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -620,22 +690,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] name = "pest" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" +checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a" dependencies = [ "thiserror", "ucd-trie", @@ -643,20 +713,20 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" +checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d" dependencies = [ "once_cell", "pest", - "sha-1", + "sha1", ] [[package]] name = "pest_vm" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16f91ae87631532461c733bf48e0a988056b23bf1ecba6cdee0bf72b623e5d5" +checksum = "266589a43e1351b2233db0e1438414f752c9af38fea696715a78739a2454a6dc" dependencies = [ "pest", "pest_meta", @@ -752,20 +822,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "serde" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfc62771e7b829b517cb213419236475f434fb480eddd76112ae182d274434a" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" dependencies = [ "js-sys", "serde", @@ -774,9 +850,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -785,9 +861,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" dependencies = [ "itoa", "ryu", @@ -795,10 +871,10 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "sha1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", @@ -848,9 +924,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "static_assertions" @@ -892,18 +968,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -935,9 +1011,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "unicode-ident" @@ -947,15 +1023,15 @@ checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "uriparse" @@ -987,9 +1063,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -997,9 +1073,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", @@ -1012,9 +1088,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1022,9 +1098,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -1035,9 +1111,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "winapi" @@ -1076,39 +1152,96 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/Cargo.toml b/Cargo.toml index 1709e2e..18cb4fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" [dependencies] cbor_event = "2.1.3" -cddl = { git = 'https://github.com/anweiss/cddl', branch = 'dcSpark-ast-parent-pointer' } +cddl = "0.9.1" clap = { version = "~3.1.5", features = ["derive"] } codegen = "0.1.3" either = "1.5.3" diff --git a/src/intermediate.rs b/src/intermediate.rs index 3ee5628..4983b2a 100644 --- a/src/intermediate.rs +++ b/src/intermediate.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; use cbor_event::Type as CBORType; use cbor_event::Special as CBORSpecial; +use cddl::ast::parent::ParentVisitor; use crate::cli::CLI_ARGS; // TODO: move all of these generation specifics into generation.rs @@ -51,6 +52,22 @@ impl<'a> IntermediateTypes<'a> { } } + pub fn has_ident(&self, ident: &RustIdent) -> bool { + let foo: Vec = self.type_aliases.keys().fold(vec![], |mut acc, alias| { + match alias { + AliasIdent::Reserved(_) => {}, + AliasIdent::Rust(ident) => { acc.push(ident.clone()) } + }; + acc + }); + println!("{:?}", self.plain_groups.keys().chain(foo.iter()).chain(self.rust_structs.keys()).chain(self.generic_defs.keys()).chain(self.generic_instances.keys())); + self.plain_groups.contains_key(ident) + || self.type_aliases.contains_key(&AliasIdent::Rust(ident.clone())) + || self.rust_structs.contains_key(ident) + || self.generic_defs.contains_key(ident) + || self.generic_instances.contains_key(ident) + } + pub fn type_aliases(&self) -> &BTreeMap { &self.type_aliases } @@ -158,12 +175,12 @@ impl<'a> IntermediateTypes<'a> { } // this is called by register_table_type / register_array_type automatically - pub fn register_rust_struct(&mut self, rust_struct: RustStruct) { + pub fn register_rust_struct(&mut self, parent_visitor: &ParentVisitor, rust_struct: RustStruct) { match &rust_struct.variant { RustStructType::Table { domain, range } => { // we must provide the keys type to return if CLI_ARGS.wasm { - self.create_and_register_array_type(domain.clone(), &domain.name_as_wasm_array()); + self.create_and_register_array_type(parent_visitor, domain.clone(), &domain.name_as_wasm_array()); } if rust_struct.tag.is_none() { self.register_type_alias( @@ -197,7 +214,7 @@ impl<'a> IntermediateTypes<'a> { // creates a RustType for the array type - and if needed, registers a type to generate // TODO: After the split we should be able to only register it directly // and then examine those at generation-time and handle things ALWAYS as RustType::Array - pub fn create_and_register_array_type(&mut self, element_type: RustType, array_type_name: &str) -> RustType { + pub fn create_and_register_array_type(&mut self, parent_visitor: &ParentVisitor, element_type: RustType, array_type_name: &str) -> RustType { let raw_arr_type = RustType::Array(Box::new(element_type.clone())); // only generate an array wrapper if we can't wasm-expose it raw if raw_arr_type.directly_wasm_exposable() { @@ -207,11 +224,11 @@ impl<'a> IntermediateTypes<'a> { // If we are the only thing referring to our element and it's a plain group // we must mark it as being serialized as an array if let RustType::Rust(_) = &element_type { - self.set_rep_if_plain_group(&array_type_ident, Representation::Array); + self.set_rep_if_plain_group(parent_visitor, &array_type_ident, Representation::Array); } // we don't pass in tags here. If a tag-wrapped array is done I think it generates // 2 separate types (array wrapper -> tag wrapper struct) - self.register_rust_struct(RustStruct::new_array(array_type_ident, None, element_type.clone())); + self.register_rust_struct(parent_visitor, RustStruct::new_array(array_type_ident, None, element_type.clone())); RustType::Array(Box::new(element_type)) } @@ -226,12 +243,12 @@ impl<'a> IntermediateTypes<'a> { } // call this after all types have been registered - pub fn finalize(&mut self) { + pub fn finalize(&mut self, parent_visitor: &ParentVisitor) { // resolve generics // resolve then register in 2 phases to get around borrow checker let resolved_generics = self.generic_instances.values().map(|instance| instance.resolve(self)).collect::>(); for resolved_instance in resolved_generics { - self.register_rust_struct(resolved_instance); + self.register_rust_struct(parent_visitor, resolved_instance); } // recursively check all types used as keys or contained within a type used as a key // this is so we only derive comparison or hash traits for those types @@ -278,7 +295,7 @@ impl<'a> IntermediateTypes<'a> { } // see self.plain_groups comments - pub fn set_rep_if_plain_group(&mut self, ident: &RustIdent, rep: Representation) { + pub fn set_rep_if_plain_group(&mut self, parent_visitor: &ParentVisitor, ident: &RustIdent, rep: Representation) { if let Some(plain_group) = self.plain_groups.get(ident) { // the clone is to get around the borrow checker if let Some(group) = plain_group.as_ref().map(|g| g.clone()) { @@ -295,7 +312,7 @@ impl<'a> IntermediateTypes<'a> { } else { // you can't tag plain groups hence the None // we also don't support generics in plain groups hence the other None - crate::parsing::parse_group(self, &group, ident, rep, None, None); + crate::parsing::parse_group(self, parent_visitor, &group, ident, rep, None, None); } } else { // If plain_group is None, then this wasn't defined in .cddl but instead @@ -382,7 +399,8 @@ impl<'a> IntermediateTypes<'a> { let def = format!("prelude_{} = {}\n", cddl_name, cddl_prelude(&cddl_name).unwrap()); let cddl = cddl::parser::cddl_from_str(&def, true).unwrap(); assert_eq!(cddl.rules.len(), 1); - crate::parsing::parse_rule(self, cddl.rules.first().unwrap()); + let pv = ParentVisitor::new(&cddl).unwrap(); + crate::parsing::parse_rule(self, &pv, cddl.rules.first().unwrap()); } } } @@ -1736,4 +1754,13 @@ impl GenericInstance { } orig.clone() } -} \ No newline at end of file +} + +fn try_ident_with_id(intermediate_types: &IntermediateTypes, name: &CDDLIdent, value: u32) -> CDDLIdent { + let new_ident = CDDLIdent::new(format!("{}{}", name, value)); + let rust_ident = RustIdent::new(new_ident.clone()); + match intermediate_types.has_ident(&rust_ident) { + false => new_ident, + true => try_ident_with_id(intermediate_types, name, value + 1) + } +} diff --git a/src/main.rs b/src/main.rs index 456793c..411a23e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,7 @@ fn main() -> Result<(), Box> { // we must group all files together. To mark scope we insert string constants with // a specific, unlikely to ever be used, prefix. The names contain a number after // to avoid a parsing error (rule with same identifier already defined). - // This approeach was chosen over comments as those were finicky when not attached + // This approach was chosen over comments as those were finicky when not attached // to specific structs, and the existing comment parsing ast was not suited for this. // If, in the future, cddl released a feature flag to allow partial cddl we can just // remove all this and revert back the commit before this one for scope handling. @@ -70,6 +70,7 @@ fn main() -> Result<(), Box> { // Plain group / scope marking let cddl = cddl::parser::cddl_from_str(&input_files_content, true)?; + let pv = cddl::ast::parent::ParentVisitor::new(&cddl).unwrap(); let mut types = IntermediateTypes::new(); // mark scope and filter scope markers let mut scope = "lib".to_owned(); @@ -102,9 +103,9 @@ fn main() -> Result<(), Box> { // Creating intermediate form from the CDDL for cddl_rule in dep_graph::topological_rule_order(&cddl_rules) { println!("\n\n------------------------------------------\n- Handling rule: {}\n------------------------------------", scope); - parse_rule(&mut types, cddl_rule); + parse_rule(&mut types, &pv, cddl_rule); } - types.finalize(); + types.finalize(&pv); // Generating code from intermediate form println!("\n-----------------------------------------\n- Generating code...\n------------------------------------"); diff --git a/src/parsing.rs b/src/parsing.rs index d7dedbc..fb917ae 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -1,4 +1,5 @@ -use cddl::ast::*; +use cddl::ast::parent::ParentVisitor; +use cddl::{ast::*, token}; use either::{Either}; use std::collections::{BTreeMap}; @@ -33,11 +34,6 @@ enum ControlOperator { CBOR(RustType), } -struct Type2AndParent<'a> { - type2: &'a Type2<'a>, - parent: &'a Type1<'a>, -} - pub const SCOPE_MARKER: &'static str = "_CDDL_CODEGEN_SCOPE_MARKER_"; /// Some means it is a scope marker, containing the scope @@ -57,7 +53,7 @@ pub fn rule_is_scope_marker(cddl_rule: &cddl::ast::Rule) -> Option { } } -pub fn parse_rule(types: &mut IntermediateTypes, cddl_rule: &cddl::ast::Rule) { +pub fn parse_rule(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, cddl_rule: &cddl::ast::Rule) { match cddl_rule { cddl::ast::Rule::Type{ rule, .. } => { // (1) is_type_choice_alternate ignored since shelley.cddl doesn't need it @@ -71,9 +67,9 @@ pub fn parse_rule(types: &mut IntermediateTypes, cddl_rule: &cddl::ast::Rule) { .map(|gp| gp.params.iter().map(|id| RustIdent::new(CDDLIdent::new(id.param.to_string()))).collect::>()); if rule.value.type_choices.len() == 1 { let choice = &rule.value.type_choices.first().unwrap(); - parse_type(types, &rust_ident, choice, None, generic_params); + parse_type(types, parent_visitor, &rust_ident, choice, None, generic_params); } else { - parse_type_choices(types, &rust_ident, &rule.value.type_choices, None, generic_params); + parse_type_choices(types, parent_visitor, &rust_ident, &rule.value.type_choices, None, generic_params); } }, cddl::ast::Rule::Group{ rule, .. } => { @@ -98,7 +94,7 @@ pub fn rule_ident(cddl_rule: &cddl::ast::Rule) -> RustIdent { } } -fn parse_type_choices(types: &mut IntermediateTypes, name: &RustIdent, type_choices: &Vec, tag: Option, generic_params: Option>) { +fn parse_type_choices(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, name: &RustIdent, type_choices: &Vec, tag: Option, generic_params: Option>) { let optional_inner_type = if type_choices.len() == 2 { let a = &type_choices[0].type1; let b = &type_choices[1].type1; @@ -118,18 +114,18 @@ fn parse_type_choices(types: &mut IntermediateTypes, name: &RustIdent, type_choi // but that won't happen with T / null types since we generate an alias instead todo!("support foo = T / null"); } - let inner_rust_type = rust_type_from_type1(types, inner_type2); + let inner_rust_type = rust_type_from_type1(types, parent_visitor, inner_type2); let final_type = match tag { Some(tag) => RustType::Tagged(tag, Box::new(RustType::Optional(Box::new(inner_rust_type)))), None => RustType::Optional(Box::new(inner_rust_type)), }; types.register_type_alias(name.clone(), final_type, true, true); } else { - let variants = create_variants_from_type_choices(types, type_choices); + let variants = create_variants_from_type_choices(types, parent_visitor, type_choices); let rust_struct = RustStruct::new_type_choice(name.clone(), tag, variants); match generic_params { Some(params) => types.register_generic_def(GenericDef::new(params, rust_struct)), - None => types.register_rust_struct(rust_struct), + None => types.register_rust_struct(parent_visitor, rust_struct), }; } } @@ -142,8 +138,8 @@ fn type2_to_number_literal(type2: &Type2) -> isize { } } -fn parse_control_operator(types: &mut IntermediateTypes, parent: &Type2AndParent, operator: &Operator) -> ControlOperator { - let lower_bound = match parent.type2 { +fn parse_control_operator(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type2: &Type2, operator: &Operator) -> ControlOperator { + let lower_bound = match type2 { Type2::Typename{ ident, .. } if ident.to_string() == "uint" => Some(0), _ => None, }; @@ -151,10 +147,10 @@ fn parse_control_operator(types: &mut IntermediateTypes, parent: &Type2AndParent // (rangeop / ctlop) S type2 match operator.operator { RangeCtlOp::RangeOp{ is_inclusive, .. } => { - let range_start = match parent.type2 { + let range_start = match type2 { Type2::UintValue{ value, .. } => *value as isize, Type2::IntValue{ value, .. } => *value, - _ => panic!("Number expected as range start. Found {:?}", parent.type2) + _ => panic!("Number expected as range start. Found {:?}", type2) }; let range_end = match operator.type2 { Type2::UintValue{ value, .. } => value as isize, @@ -164,20 +160,20 @@ fn parse_control_operator(types: &mut IntermediateTypes, parent: &Type2AndParent ControlOperator::Range((Some(range_start as i128), Some(if is_inclusive { range_end as i128 } else { (range_end + 1) as i128 }))) }, RangeCtlOp::CtlOp{ ctrl, .. } => match ctrl { - ".default" | - ".cborseq" | - ".within" | - ".and" => todo!("control operator {} not supported", ctrl), - ".cbor" => ControlOperator::CBOR(rust_type_from_type2(types, &Type2AndParent { type2: &operator.type2, parent: parent.parent, })), - ".eq" => ControlOperator::Range((Some(type2_to_number_literal(&operator.type2) as i128), Some(type2_to_number_literal(&operator.type2) as i128))), + token::ControlOperator::DEFAULT | + token::ControlOperator::CBORSEQ | + token::ControlOperator::WITHIN | + token::ControlOperator::AND => todo!("control operator {} not supported", ctrl), + token::ControlOperator::CBOR => ControlOperator::CBOR(rust_type_from_type2(types, parent_visitor, &operator.type2)), + token::ControlOperator::EQ => ControlOperator::Range((Some(type2_to_number_literal(&operator.type2) as i128), Some(type2_to_number_literal(&operator.type2) as i128))), // TODO: this would be MUCH nicer (for error displaying, etc) to handle this in its own dedicated way // which might be necessary once we support other control operators anyway - ".ne" => ControlOperator::Range((Some((type2_to_number_literal(&operator.type2) + 1) as i128), Some((type2_to_number_literal(&operator.type2) - 1) as i128))), - ".le" => ControlOperator::Range((lower_bound, Some(type2_to_number_literal(&operator.type2) as i128))), - ".lt" => ControlOperator::Range((lower_bound, Some((type2_to_number_literal(&operator.type2) - 1) as i128))), - ".ge" => ControlOperator::Range((Some(type2_to_number_literal(&operator.type2) as i128), None)), - ".gt" => ControlOperator::Range((Some((type2_to_number_literal(&operator.type2) + 1) as i128), None)), - ".size" => { + token::ControlOperator::NE => ControlOperator::Range((Some((type2_to_number_literal(&operator.type2) + 1) as i128), Some((type2_to_number_literal(&operator.type2) - 1) as i128))), + token::ControlOperator::LE => ControlOperator::Range((lower_bound, Some(type2_to_number_literal(&operator.type2) as i128))), + token::ControlOperator::LT => ControlOperator::Range((lower_bound, Some((type2_to_number_literal(&operator.type2) - 1) as i128))), + token::ControlOperator::GE => ControlOperator::Range((Some(type2_to_number_literal(&operator.type2) as i128), None)), + token::ControlOperator::GT => ControlOperator::Range((Some((type2_to_number_literal(&operator.type2) + 1) as i128), None)), + token::ControlOperator::SIZE => { let base_range = match &operator.type2 { Type2::UintValue{ value, .. } => ControlOperator::Range((None, Some(*value as i128))), Type2::IntValue{ value, .. } => ControlOperator::Range((None, Some(*value as i128))), @@ -207,7 +203,7 @@ fn parse_control_operator(types: &mut IntermediateTypes, parent: &Type2AndParent }, _ => unimplemented!("unsupported type in range control operator: {:?}", operator), }; - match parent.type2 { + match type2 { Type2::Typename{ ident, .. } if ident.to_string() == "uint" => { // .size 3 means 24 bits match &base_range { @@ -252,14 +248,14 @@ fn range_to_primitive(low: Option, high: Option) -> Option } } -fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: &TypeChoice, outer_tag: Option, generic_params: Option>) { +fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type_name: &RustIdent, type_choice: &TypeChoice, outer_tag: Option, generic_params: Option>) { let type1 = &type_choice.type1; match &type1.type2 { Type2::Typename{ ident, generic_args, .. } => { // Note: this handles bool constants too, since we apply the type aliases and they resolve // and there's no Type2::BooleanValue let cddl_ident = CDDLIdent::new(ident.to_string()); - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, &Type2AndParent { type2: &type1.type2, parent: &type1 }, op)); + let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); match control { Some(control) => { assert!(generic_params.is_none(), "Generics combined with range specifiers not supported"); @@ -276,7 +272,7 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: Some(t) => types.register_type_alias(type_name.clone(), t, true, true), None => panic!("unsupported range for {:?}: {:?}", cddl_ident.to_string().as_str(), control) }, - _ => types.register_rust_struct(RustStruct::new_wrapper(type_name.clone(), outer_tag, field_type().clone(), Some(min_max))) + _ => types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), outer_tag, field_type().clone(), Some(min_max))) } }, ControlOperator::CBOR(ty) => match field_type() { @@ -303,13 +299,13 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: Some(arg) => { // This is for named generic instances such as: // foo = bar - let generic_args = arg.args.iter().map(|a| rust_type_from_type1(types, &a.arg)).collect(); + let generic_args = arg.args.iter().map(|a| rust_type_from_type1(types, parent_visitor, &a.arg)).collect(); types.register_generic_instance(GenericInstance::new(type_name.clone(), RustIdent::new(cddl_ident.clone()), generic_args)) }, None => { let rule_metadata = RuleMetadata::from(type1.comments_after_type.as_ref()); if rule_metadata.is_newtype { - types.register_rust_struct(RustStruct::new_wrapper(type_name.clone(), None, concrete_type, None)); + types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), None, concrete_type, None)); } else { types.register_type_alias(type_name.clone(), concrete_type, true, true); } @@ -321,12 +317,12 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: } }, Type2::Map{ group, .. } => { - parse_group(types, group, type_name, Representation::Map, outer_tag, generic_params); + parse_group(types, parent_visitor, group, type_name, Representation::Map, outer_tag, generic_params); }, Type2::Array{ group, .. } => { // TODO: We could potentially generate an array-wrapper type around this // possibly based on the occurency specifier. - parse_group(types, group, type_name, Representation::Array, outer_tag, generic_params); + parse_group(types, parent_visitor, group, type_name, Representation::Array, outer_tag, generic_params); }, Type2::TaggedData{ tag, t, .. } => { if let Some(_) = outer_tag { @@ -342,10 +338,10 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: Type2::Array{ group, .. } => Either::Left(group), x => panic!("only supports tagged arrays/maps/typenames - found: {:?} in rule {}", x, type_name), } { - Either::Left(_group) => parse_type(types, type_name, inner_type, *tag, generic_params), + Either::Left(_group) => parse_type(types, parent_visitor, type_name, inner_type, *tag, generic_params), Either::Right(ident) => { let new_type = types.new_type(&CDDLIdent::new(ident.to_string())); - let control = inner_type.type1.operator.as_ref().map(|op| parse_control_operator(types, &Type2AndParent { parent: &inner_type.type1, type2: &inner_type.type1.type2 }, op)); + let control = inner_type.type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &inner_type.type1.type2, op)); match control { Some(ControlOperator::CBOR(ty)) => { // TODO: this would be fixed if we ordered definitions via a dependency graph to begin with @@ -361,7 +357,7 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: Some(t) => types.register_type_alias(type_name.clone(), t, true, true), None => panic!("unsupported range for {:?}: {:?}", ident.to_string().as_str(), control) }, - _ => types.register_rust_struct(RustStruct::new_wrapper(type_name.clone(), *tag, new_type, Some(min_max))) + _ => types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), *tag, new_type, Some(min_max))) } }, None => { @@ -377,7 +373,7 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: }; }, _ => { - parse_type_choices(types, type_name, &t.type_choices, *tag, generic_params); + parse_type_choices(types, parent_visitor, type_name, &t.type_choices, *tag, generic_params); } }; }, @@ -385,7 +381,7 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: Type2::IntValue{ value, .. } => { let fallback_type = RustType::Fixed(FixedValue::Nint(*value)); - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, &Type2AndParent { parent: type1, type2: &type1.type2 }, op)); + let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); let base_type = match control { Some(ControlOperator::Range(min_max)) => { match range_to_primitive(min_max.0, min_max.1) { @@ -400,7 +396,7 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: Type2::UintValue{ value, .. } => { let fallback_type = RustType::Fixed(FixedValue::Uint(*value)); - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, &Type2AndParent { parent: type1, type2: &type1.type2 }, op)); + let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); let base_type = match control { Some(ControlOperator::Range(min_max)) => { match range_to_primitive(min_max.0, min_max.1) { @@ -422,10 +418,10 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice: } // TODO: Also generates individual choices if required, ie for a / [foo] / c would generate Foos -pub fn create_variants_from_type_choices(types: &mut IntermediateTypes, type_choices: &Vec) -> Vec { +pub fn create_variants_from_type_choices(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type_choices: &Vec) -> Vec { let mut variant_names_used = BTreeMap::::new(); type_choices.iter().map(|choice| { - let rust_type = rust_type_from_type1(types, &choice.type1); + let rust_type = rust_type_from_type1(types, parent_visitor, &choice.type1); let variant_name = append_number_if_duplicate(&mut variant_names_used, rust_type.for_variant().to_string()); EnumVariant::new(VariantIdent::new_custom(variant_name), rust_type, false) }).collect() @@ -596,8 +592,8 @@ fn group_entry_to_raw_field_name(entry: &GroupEntry) -> Option { } } -fn rust_type_from_type1(types: &mut IntermediateTypes, type1: &Type1) -> RustType { - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, &Type2AndParent { parent: type1, type2: &type1.type2 }, op)); +fn rust_type_from_type1(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type1: &Type1) -> RustType { + let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); // println!("type1: {:#?}", type1); match control { Some(ControlOperator::CBOR(ty)) => RustType::CBORBytes(Box::new(ty)), @@ -607,16 +603,16 @@ fn rust_type_from_type1(types: &mut IntermediateTypes, type1: &Type1) -> RustTyp Some(t) => t, None => panic!("unsupported range for {:?}: {:?}", ident.to_string().as_str(), control) }, - _ => rust_type_from_type2(types, &Type2AndParent { type2: &type1.type2, parent: type1, }) + _ => rust_type_from_type2(types, parent_visitor, &type1.type2) } }, - _ => rust_type_from_type2(types, &Type2AndParent { type2: &type1.type2, parent: type1, }) + _ => rust_type_from_type2(types, parent_visitor, &type1.type2) } } -fn rust_type_from_type2(types: &mut IntermediateTypes, type2: &Type2AndParent) -> RustType { +fn rust_type_from_type2(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type2: &Type2) -> RustType { // TODO: socket plugs (used in hash type) - match &type2.type2 { + match &type2 { Type2::UintValue{ value, .. } => RustType::Fixed(FixedValue::Uint(*value)), Type2::IntValue{ value, .. } => RustType::Fixed(FixedValue::Nint(*value)), //Type2::FloatValue{ value, .. } => RustType::Fixed(FixedValue::Float(*value)), @@ -629,7 +625,7 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, type2: &Type2AndParent) - // foo = [a: bar] // so to be able to expose it to wasm, we create a new generic instance // under the name bar_string_bool in this case. - let generic_args = args.args.iter().map(|a| rust_type_from_type1(types, &a.arg)).collect::>(); + let generic_args = args.args.iter().map(|a| rust_type_from_type1(types, parent_visitor, &a.arg)).collect::>(); let args_name = generic_args.iter().map(|t| t.for_variant().to_string()).collect::>().join("_"); let instance_cddl_ident = CDDLIdent::new(format!("{}_{}", cddl_ident, args_name)); let instance_ident = RustIdent::new(instance_cddl_ident.clone()); @@ -649,19 +645,19 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, type2: &Type2AndParent) - if choice.group_entries.len() == 1 { let (entry, _has_comma) = choice.group_entries.first().unwrap(); match entry { - GroupEntry::ValueMemberKey{ ge, .. } => rust_type(types, &ge.entry_type), + GroupEntry::ValueMemberKey{ ge, .. } => rust_type(types, parent_visitor, &ge.entry_type), GroupEntry::TypeGroupname{ ge, .. } => types.new_type(&CDDLIdent::new(&ge.name.to_string())), _ => panic!("UNSUPPORTED_ARRAY_ELEMENT<{:?}>", entry), } } else { - let rule_metadata = RuleMetadata::from(type2.parent.comments_after_type.as_ref()); + let rule_metadata = RuleMetadata::from(get_comment_after(parent_visitor, &CDDLType::from(type2), None).as_ref());; let name = match rule_metadata.name.as_ref() { Some(name) => name, None => panic!("Anonymous groups not allowed. Either create an explicit rule (foo = [0, bytes]) or give it a name using the @name notation. Group: {:#?}", group) }; let cddl_ident = CDDLIdent::new(name); let rust_ident = RustIdent::new(cddl_ident.clone()); - parse_group(types, group, &rust_ident, Representation::Array, None, None); + parse_group(types, parent_visitor, group, &rust_ident, Representation::Array, None, None); // we aren't returning an array, but rather a struct where the fields are ordered return types.new_type(&cddl_ident) } @@ -682,8 +678,8 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, type2: &Type2AndParent) - match table_types { // Table map - homogenous key/value types Some((domain, range)) => { - let key_type = rust_type_from_type1(types, domain); - let value_type = rust_type(types, range); + let key_type = rust_type_from_type1(types, parent_visitor, domain); + let value_type = rust_type(types, parent_visitor, range); // Generate a MapTToV for a { t => v } table-type map as we are an anonymous type // defined as part of another type if we're in this level of parsing. // We also can't have plain groups unlike arrays, so don't try and generate those @@ -700,30 +696,30 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, type2: &Type2AndParent) - }, // unsure if we need to handle the None case - when does this happen? Type2::TaggedData{ tag, t, .. } => { - RustType::Tagged(tag.expect("tagged data without tag not supported"), Box::new(rust_type(types, t))) + RustType::Tagged(tag.expect("tagged data without tag not supported"), Box::new(rust_type(types, parent_visitor, t))) }, _ => { - panic!("Ignoring Type2: {:?}", type2.type2); + panic!("Ignoring Type2: {:?}", type2); }, } } -fn rust_type(types: &mut IntermediateTypes, t: &Type) -> RustType { +fn rust_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, t: &Type) -> RustType { if t.type_choices.len() == 1 { - rust_type_from_type1(types, &t.type_choices.first().unwrap().type1) + rust_type_from_type1(types, parent_visitor, &t.type_choices.first().unwrap().type1) } else { if t.type_choices.len() == 2 { // T / null or null / T should map to Option let a = &t.type_choices[0].type1; let b = &t.type_choices[1].type1; if type2_is_null(&a.type2) { - return RustType::Optional(Box::new(rust_type_from_type1(types, b))); + return RustType::Optional(Box::new(rust_type_from_type1(types, parent_visitor, b))); } if type2_is_null(&b.type2) { - return RustType::Optional(Box::new(rust_type_from_type1(types, a))); + return RustType::Optional(Box::new(rust_type_from_type1(types, parent_visitor, a))); } } - let variants = create_variants_from_type_choices(types, &t.type_choices); + let variants = create_variants_from_type_choices(types, parent_visitor, &t.type_choices); let mut combined_name = String::new(); // one caveat: nested types can leave ambiguous names and cause problems like // (a / b) / c and a / (b / c) would both be AOrBOrC @@ -735,7 +731,7 @@ fn rust_type(types: &mut IntermediateTypes, t: &Type) -> RustType { combined_name.push_str(&variant.rust_type.for_variant().to_string()); } let combined_ident = RustIdent::new(CDDLIdent::new(&combined_name)); - types.register_rust_struct(RustStruct::new_type_choice(combined_ident, None, variants)); + types.register_rust_struct(parent_visitor, RustStruct::new_type_choice(combined_ident, None, variants)); types.new_type(&CDDLIdent::new(combined_name)) } } @@ -755,9 +751,9 @@ fn group_entry_optional(entry: &GroupEntry) -> bool { .unwrap_or(false) } -fn group_entry_to_type(types: &mut IntermediateTypes, entry: &GroupEntry) -> RustType { +fn group_entry_to_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, entry: &GroupEntry) -> RustType { let ret = match entry { - GroupEntry::ValueMemberKey{ ge, .. } => rust_type(types, &ge.entry_type), + GroupEntry::ValueMemberKey{ ge, .. } => rust_type(types, parent_visitor, &ge.entry_type), GroupEntry::TypeGroupname{ ge, .. } => { if ge.generic_args.is_some() { // I am not sure how we end up with this kind of generic args since definitional ones @@ -799,15 +795,15 @@ fn group_entry_to_key(entry: &GroupEntry) -> Option { } } -fn parse_record_from_group_choice(types: &mut IntermediateTypes, rep: Representation, group_choice: &GroupChoice) -> RustRecord { +fn parse_record_from_group_choice(types: &mut IntermediateTypes, rep: Representation, parent_visitor: &ParentVisitor, group_choice: &GroupChoice) -> RustRecord { let mut generated_fields = BTreeMap::::new(); let fields = group_choice.group_entries.iter().enumerate().map( |(index, (group_entry, optional_comma))| { let field_name = group_entry_to_field_name(group_entry, index, &mut generated_fields, optional_comma); // does not exist for fixed values importantly - let field_type = group_entry_to_type(types, group_entry); + let field_type = group_entry_to_type(types, parent_visitor, group_entry); if let RustType::Rust(ident) = &field_type { - types.set_rep_if_plain_group(ident, rep); + types.set_rep_if_plain_group(parent_visitor, ident, rep); } let optional_field = group_entry_optional(group_entry); let key = match rep { @@ -823,32 +819,32 @@ fn parse_record_from_group_choice(types: &mut IntermediateTypes, rep: Representa } } -fn parse_group_choice<'a>(types: &mut IntermediateTypes, group_choice: &'a GroupChoice, name: &RustIdent, rep: Representation, tag: Option, generic_params: Option>) { +fn parse_group_choice<'a>(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, group_choice: &'a GroupChoice, name: &RustIdent, rep: Representation, tag: Option, generic_params: Option>) { let table_types = table_domain_range(group_choice, rep); let rust_struct = match table_types { // Table map - homogenous key/value types Some((domain, range)) => { - let key_type = rust_type_from_type1(types, domain); - let value_type = rust_type(types, range); + let key_type = rust_type_from_type1(types, parent_visitor, domain); + let value_type = rust_type(types, parent_visitor, range); RustStruct::new_table(name.clone(), tag, key_type, value_type) }, // Heterogenous map (or array!) with defined key/value pairs in the cddl like a struct None => { - let record = parse_record_from_group_choice(types, rep, group_choice); + let record = parse_record_from_group_choice(types, rep, parent_visitor, group_choice); // We need to store this in IntermediateTypes so we can refer from one struct to another. RustStruct::new_record(name.clone(), tag, record) } }; match generic_params { Some(params) => types.register_generic_def(GenericDef::new(params, rust_struct)), - None => types.register_rust_struct(rust_struct), + None => types.register_rust_struct(parent_visitor, rust_struct), }; } -pub fn parse_group(types: &mut IntermediateTypes, group: &Group, name: &RustIdent, rep: Representation, tag: Option, generic_params: Option>) { +pub fn parse_group(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, group: &Group, name: &RustIdent, rep: Representation, tag: Option, generic_params: Option>) { if group.group_choices.len() == 1 { // Handle simple (no choices) group. - parse_group_choice(types, group.group_choices.first().unwrap(), name, rep, tag, generic_params); + parse_group_choice(types, parent_visitor, group.group_choices.first().unwrap(), name, rep, tag, generic_params); } else { if generic_params.is_some() { todo!("{}: generic group choices not supported", name); @@ -870,10 +866,10 @@ pub fn parse_group(types: &mut IntermediateTypes, group: &Group, name: &RustIden // We might end up doing this anyway to support table-maps in choices though. if group_choice.group_entries.len() == 1 { let group_entry = &group_choice.group_entries.first().unwrap().0; - let ty = group_entry_to_type(types, group_entry); + let ty = group_entry_to_type(types, parent_visitor, group_entry); let serialize_as_embedded = if let RustType::Rust(ident) = &ty { // we might need to generate it if not used elsewhere - types.set_rep_if_plain_group(ident, rep); + types.set_rep_if_plain_group(parent_visitor, ident, rep); types.is_plain_group(ident) } else { false @@ -900,10 +896,148 @@ pub fn parse_group(types: &mut IntermediateTypes, group: &Group, name: &RustIden // General case, GroupN type identifiers and generate group choice since it's inlined here let variant_name = RustIdent::new(CDDLIdent::new(ident_name)); types.mark_plain_group(variant_name.clone(), None); - parse_group_choice(types, group_choice, &variant_name, rep, None, generic_params.clone()); + parse_group_choice(types, parent_visitor, group_choice, &variant_name, rep, None, generic_params.clone()); EnumVariant::new(VariantIdent::new_rust(variant_name.clone()), RustType::Rust(variant_name), true) } }).collect(); - types.register_rust_struct(RustStruct::new_group_choice(name.clone(), tag, variants, rep)); + types.register_rust_struct(parent_visitor, RustStruct::new_group_choice(name.clone(), tag, variants, rep)); + } +} + +fn get_comments_if_group_parent<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &CDDLType<'a, 'a>, child: Option<&CDDLType<'a, 'a>>, comments_after_group: &Option>) -> Option> { + if let Some(CDDLType::Group(_)) = child { + return comments_after_group.clone() + } + get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)) +} +fn get_comments_if_type_parent<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &CDDLType<'a, 'a>, child: Option<&CDDLType<'a, 'a>>, comments_after_type: &Option>) -> Option> { + if let Some(CDDLType::Type(_)) = child { + return comments_after_type.clone() + } + get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)) +} + + +/// Gets the comment(s) that come after a type by parsing the CDDL AST +/// +/// (implementation detail) sometimes getting the comment after a type requires walking up the AST +/// This happens when whether or not the type has a comment after it depends in which structure it is embedded in +/// For example, CDDLType::Group has no "comment_after_group" type +/// However, when part of a Type2::Array, it does have a "comment_after_group" embedded inside the Type2 +/// +/// Note: we do NOT merge comments when the type is coincidentally the last node inside its parent structure +/// For example, the last CDDLType::GroupChoice inside a CDDLType::Group will not return its parent's comment +fn get_comment_after<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &CDDLType<'a, 'a>, child: Option<&CDDLType<'a, 'a>>) -> Option> { + match cddl_type { + CDDLType::CDDL(_) => None, + CDDLType::Rule(t) => + match t { + Rule::Type { comments_after_rule, .. } => comments_after_rule.clone(), + Rule::Group { comments_after_rule, .. } => comments_after_rule.clone(), + }, + CDDLType::TypeRule(_) => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), + CDDLType::GroupRule(_) => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), + CDDLType::Group(_) => { + match cddl_type.parent(parent_visitor).unwrap() { + parent@CDDLType::GroupEntry(_) => get_comment_after(parent_visitor, parent, Some(cddl_type)), + parent@CDDLType::Type2(_) => get_comment_after(parent_visitor, parent, Some(cddl_type)), + parent@CDDLType::MemberKey(_) => get_comment_after(parent_visitor, parent, Some(cddl_type)), + _ => None, + } + }, + // TODO: handle child by looking up the group entry in group_entries + // the expected behavior of this may instead be to combine_comments based off its parents + // which is a slippery slope in complexity + CDDLType::GroupChoice(_) => None, + CDDLType::GenericParams(_) => None, + CDDLType::GenericParam(t) => { + if let Some(CDDLType::Identifier(_)) = child { + return t.comments_after_ident.clone() + } + None + }, + CDDLType::GenericArgs(_) => None, + CDDLType::GenericArg(t) => { + if let Some(CDDLType::Type1(_)) = child { + return t.comments_after_type.clone() + } + None + }, + CDDLType::GroupEntry(t) => match t { + GroupEntry::ValueMemberKey { trailing_comments, .. } => trailing_comments.clone(), + GroupEntry::TypeGroupname { trailing_comments, .. } => trailing_comments.clone(), + GroupEntry::InlineGroup { comments_after_group, .. } => { + if let Some(CDDLType::Group(_)) = child { + return comments_after_group.clone() + } + None + }, + }, + CDDLType::Identifier(_) => None, // TODO: recurse up for GenericParam + CDDLType::Type(_) => None, + CDDLType::TypeChoice(t) => t.comments_after_type.clone(), + CDDLType::Type1(t) => { + if let Some(CDDLType::Type2(_)) = child { + if let Some(op) = &t.operator { + return op.comments_before_operator.clone() + } else { + return t.comments_after_type.clone() + } + }; + if t.operator.is_none() { + get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)) + } else { + None + } + }, + CDDLType::Type2(t) => match t { + Type2::ParenthesizedType { comments_after_type, .. } => get_comments_if_type_parent(parent_visitor, cddl_type, child, comments_after_type), + Type2::Map { comments_after_group, .. } => get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group), + Type2::Array { comments_after_group, .. } => get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group), + Type2::Unwrap { .. } => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), + Type2::ChoiceFromInlineGroup { comments_after_group, .. } => get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group), + Type2::ChoiceFromGroup { .. } => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), + Type2::TaggedData { comments_after_type, .. } => get_comments_if_type_parent(parent_visitor, cddl_type, child, comments_after_type), + _ => None, + }, + CDDLType::Operator(t) => { + if let Some(CDDLType::RangeCtlOp(_)) = child { + return t.comments_after_operator.clone() + } + if let Some(CDDLType::Type2(t2)) = child { + // "comments_before_operator" is associated with the 1st type2 and not the second (t.type2) + if std::ptr::eq(*t2, &t.type2) { + return None + } else { + return t.comments_before_operator.clone() + } + } + None + }, + CDDLType::Occurrence(t) => t.comments.clone(), + CDDLType::Occur(_) => None, + CDDLType::Value(_) => None, + CDDLType::ValueMemberKeyEntry(_) => None, + CDDLType::TypeGroupnameEntry(_) => None, + CDDLType::MemberKey(t) => match t { + MemberKey::NonMemberKey { comments_after_type_or_group, .. } => comments_after_type_or_group.clone(), + _ => None + }, + CDDLType::NonMemberKey(_) => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), + _ => None + } +} + +fn get_rule_name<'a, 'b>(parent_visitor: &'a ParentVisitor, cddl_type: &CDDLType<'a, 'b>) -> Identifier<'a> { + match cddl_type { + CDDLType::CDDL(_) => panic!("Cannot get the rule name of a top-level CDDL node"), + CDDLType::Rule(t) => + match t { + Rule::Type { rule, .. } => get_rule_name(parent_visitor, &CDDLType::from(rule)), + Rule::Group { rule, .. } => get_rule_name(parent_visitor, &CDDLType::from(rule.as_ref())), + }, + CDDLType::TypeRule(t) => t.name.clone(), + CDDLType::GroupRule(t) => t.name.clone(), + other => get_rule_name(parent_visitor, other.parent(parent_visitor).unwrap()), } }