From 0f5f43a5584cc3f4e7571d635a06ce126d1001dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Thu, 31 Aug 2023 21:13:29 +0200 Subject: [PATCH] feat: Add parser and tcl generator --- .gitignore | 1 + Cargo.lock | 679 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 13 + src/display_elements.rs | 150 +++++++++ src/file_parser.rs | 254 +++++++++++++++ src/main.rs | 89 ++++++ src/tcl_generator.rs | 93 ++++++ 7 files changed, 1279 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/display_elements.rs create mode 100644 src/file_parser.rs create mode 100644 src/main.rs create mode 100644 src/tcl_generator.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..90a59a77d40b97552391c26baa05acd1ecb130ea --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,679 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gtkwave_tcl_generator" +version = "0.1.0" +dependencies = [ + "clap", + "glob", + "parking_lot", + "string-builder", + "vhdl_lang", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "memchr" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76fc44e2588d5b436dbc3c6cf62aef290f90dab6235744a93dfe1cc18f451e2c" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "pad" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pinned_vec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268ad82d92622fb0a049ff14b01089b0f1bcd5c507fab44724394d328417348a" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.16", + "thiserror", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "string-builder" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd10a070fb1f2796a288abec42695db4682a82b6f12ffacd60fb8d5ad3a4a12" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "vhdl_lang" +version = "0.65.0" +source = "git+https://github.com/Rutherther/rust_hdl.git#aacf15291c3e112609d3f59bce0c4fb45ac9d637" +dependencies = [ + "clap", + "dirs", + "dunce", + "fnv", + "glob", + "itertools", + "pad", + "parking_lot", + "pinned_vec", + "rayon", + "toml", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..881300f4efcda57a7c8b81d69c46142b81eecc88 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "gtkwave_tcl_generator" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.4.1", features = ["derive"] } +glob = "0.3.1" +parking_lot = "0.12.1" +string-builder = "0.2.0" +vhdl_lang = {git = "https://github.com/Rutherther/rust_hdl.git", version = "0.65.0"} diff --git a/src/display_elements.rs b/src/display_elements.rs new file mode 100644 index 0000000000000000000000000000000000000000..dd94ee5bd69f7242bb4a16934932c3e40bdf07d7 --- /dev/null +++ b/src/display_elements.rs @@ -0,0 +1,150 @@ +use std::{slice::Iter, fmt::Display}; + +#[derive(Eq, PartialEq, Clone)] +pub enum DisplayElement { + Signal(Signal), + Empty(Vec) +} + +#[derive(Eq, PartialEq, Clone, Copy)] +pub enum DisplayOption { + Color(DisplayColor), + Format(DisplayFormat), + Omit +} + +#[derive(Eq, PartialEq, Clone)] +pub struct Signal { + name: String, + options: Vec +} + +impl From<&str> for Signal { + fn from(value: &str) -> Self { + Self { + name: value.to_owned(), + options: vec![] + } + } +} + +#[derive(Eq, PartialEq, Clone)] +pub struct Entity { + name: String, + architecture: Option, +} + +#[derive(Eq, PartialEq, Clone)] +pub struct Architecture { + name: String, + entity_name: String, + signals: Vec +} + +#[derive(Eq, PartialEq, Copy, Clone)] +pub enum DisplayColor { + Normal, + Red, + Orange, + Yellow, + Green, + Blue, + Indigo, + Violet, + Cycle, +} + +impl Display for DisplayColor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + DisplayColor::Normal => "Normal", + DisplayColor::Red => "Red", + DisplayColor::Orange => "Orange", + DisplayColor::Yellow => "Yellow", + DisplayColor::Green => "Green", + DisplayColor::Blue => "Blue", + DisplayColor::Indigo => "Indigo", + DisplayColor::Violet => "Violet", + DisplayColor::Cycle => "Cycle", + }) + } +} + +#[derive(Eq, PartialEq, Copy, Clone)] +pub enum DisplayFormat { + Hex, + Decimal, + SignedDecimal, + Binary, +} + +impl Display for DisplayFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + DisplayFormat::Hex => "Hex", + DisplayFormat::Decimal => "Decimal", + DisplayFormat::SignedDecimal => "SignedDecimal", + DisplayFormat::Binary => "Binary", + }) + } +} + +impl Signal { + pub fn new(name: String, options: Vec) -> Self { + Self { + name, + options + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn options(&self) -> Iter<'_, DisplayOption> { + self.options.iter() + } +} + +impl Entity { + pub fn new(name: String) -> Self { + Self { + name, + architecture: None + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn add_architecture(&mut self, architecture: Architecture) { + self.architecture = Some(architecture); + } + + pub fn architecture(&self) -> Option<&Architecture> { + self.architecture.as_ref() + } +} + +impl Architecture { + pub fn new(name: String, entity_name: String, signals: Vec) -> Self { + Self { + name, + entity_name, + signals, + } + } + + pub fn signals(&self) -> Iter<'_, Signal> { + self.signals.iter() + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn entity_name(&self) -> &str { + &self.entity_name + } +} diff --git a/src/file_parser.rs b/src/file_parser.rs new file mode 100644 index 0000000000000000000000000000000000000000..bbf026cae0b7a4457edccadc5183e8363480e511 --- /dev/null +++ b/src/file_parser.rs @@ -0,0 +1,254 @@ +use vhdl_lang::{Source, syntax::{tokens::{TokenStream, Tokenizer, Kind, Comment}, Symbols}, Diagnostic, data::{Contents, ContentReader}}; + +use crate::display_elements::{DisplayColor, Entity, Architecture, Signal, DisplayOption, DisplayFormat}; + +#[derive(PartialEq, Eq, Clone)] +struct Context { + color: Option, + omit: bool +} + +pub struct FileParser<'a> { + diagnostics: Vec, + stream: TokenStream<'a>, + + entities: Vec, + current_entity: usize +} + +#[derive(Debug)] +pub enum ParseError { + EntityNotPresent, + ArchitectureNotFound, + ParsingError(Diagnostic), + EndOfFile, +} + +impl From for ParseError { + fn from(value: Diagnostic) -> Self { + Self::ParsingError(value) + } +} + +impl From<&Context> for Vec { + fn from(value: &Context) -> Self { + let mut options = vec![]; + + if value.omit { + options.push(DisplayOption::Omit); + } + + if let Some(color) = value.color { + options.push(DisplayOption::Color(color)); + } + + options + } +} + +impl<'a> FileParser<'a> { + pub fn new(source: &'a Source, contents: &'a Contents, symbols: &'a Symbols) -> Self { + let mut diagnostics = vec![]; + let tokenizer = Tokenizer::new(symbols, source, ContentReader::new(contents)); + let stream = TokenStream::new(tokenizer, &mut diagnostics); + + Self { + diagnostics, + stream, + entities: vec![], + current_entity: 0, + } + } + + pub fn find_next_entity(&mut self) -> Result { + if self.current_entity < self.entities.len() { + self.current_entity += 1; + return Ok(self.entities[self.current_entity - 1].clone()); + } + + if self.stream.skip_until(|k| k == Kind::Entity || k == Kind::Architecture).is_err() { + return Err(ParseError::EndOfFile); + } + + if self.stream.peek_kind().unwrap() == Kind::Entity { + let entity = Self::parse_entity(&mut self.stream)?; + self.entities.push(entity.clone()); + self.current_entity += 1; + + Ok(entity) + } else { + let architecture = Self::parse_architecture(&mut self.stream)?; + + if let Some(entity) = self.entities.iter_mut().find(|e| e.name() == architecture.entity_name()) { + entity.add_architecture(architecture); + } + + self.find_next_entity() + } + } + + pub fn parse_entity_architecture(&mut self, mut entity: Entity) -> Result { + let Some(found_entity) = self.entities.iter_mut().find(|e| e.name() == entity.name()) else { + return Err(ParseError::EntityNotPresent); + }; + + if entity.architecture().is_some() { + return Ok(entity); + } + + if found_entity.architecture().is_some() { + return Ok(found_entity.clone()); + } + + if self.stream.skip_until(|k| k == Kind::Entity || k == Kind::Architecture).is_err() { + return Err(ParseError::EndOfFile); + } + + if self.stream.peek_kind().unwrap() == Kind::Entity { + let entity = Self::parse_entity(&mut self.stream)?; + self.entities.push(entity.clone()); + return self.parse_entity_architecture(entity) + } + + let architecture = Self::parse_architecture(&mut self.stream)?; + if architecture.entity_name() == entity.name() { + entity.add_architecture(architecture.clone()); + found_entity.add_architecture(architecture); + + return Ok(entity); + } + + if let Some(matched_entity) = self.entities.iter_mut().find(|e| e.name() == architecture.entity_name()) { + matched_entity.add_architecture(architecture); + } + + self.parse_entity_architecture(entity) + } + + fn parse_architecture(stream: &mut TokenStream) -> Result { + stream.expect_kind(Kind::Architecture)?; + + let architecture_name = Self::parse_identifier(stream)?; + + stream.expect_kind(Kind::Of)?; + + let entity_name = Self::parse_identifier(stream)?; + + stream.expect_kind(Kind::Is)?; + + let mut context = Context { color: None, omit: false }; + let mut signals = vec![]; + + while !stream.next_kind_is(Kind::Begin) { + let token = stream.peek().ok_or(ParseError::EndOfFile)?; + + if let Some(comments) = &token.comments { + for comment in &comments.leading { + Self::update_context(&mut context, comment); + } + } + + match token.kind { + Kind::Signal => signals.append(Self::parse_signals(stream, &context)?.as_mut()), + Kind::Begin => break, + _ => stream.skip(), + } + } + + let architecture = Architecture::new(architecture_name, entity_name, signals); + + Ok(architecture) + } + + fn parse_signals(stream: &mut TokenStream, context: &Context) -> Result, ParseError> { + stream.expect_kind(Kind::Signal)?; + + let mut signal_names = vec![]; + signal_names.push(Self::parse_identifier(stream)?); + + while stream.peek_kind().ok_or(ParseError::EndOfFile)? != Kind::Colon { + stream.skip(); + signal_names.push(Self::parse_identifier(stream)?); + } + + stream.skip(); + + let signal_type = Self::parse_identifier(stream)?; + + stream.skip_until(|k| k == Kind::SemiColon)?; + let semicolon_token = stream.peek().ok_or(ParseError::EndOfFile)?; + + let options: Vec = if let Some(comments) = &semicolon_token.comments { + if let Some(trailing) = &comments.trailing { + let mut context = context.clone(); + Self::update_context(&mut context, trailing); + (&context).into() + } else { + context.into() + } + } else { + context.into() + }; + + let mut signals = vec![]; + for signal_name in signal_names { + let mut options = options.clone(); + if signal_type.starts_with("std_logic_vector") { + options.push(DisplayOption::Format(DisplayFormat::Binary)); + } + + signals.push(Signal::new(signal_name, options)); + } + + Ok(signals) + } + + fn parse_entity(stream: &mut TokenStream) -> Result { + stream.expect_kind(Kind::Entity)?; + + let name = Self::parse_identifier(stream)?; + Ok(Entity::new(name)) + } + + fn parse_identifier(stream: &mut TokenStream) -> Result { + let token = stream.peek_expect()?; + let identifier = token.to_identifier_value()?; + + stream.skip(); + + Ok(identifier.item.name_utf8()) + } + + fn update_context(context: &mut Context, comment: &Comment) { + let commands = comment.value.split(['\n', ','].as_ref()); + + for command in commands { + match command.trim() { + "omit" => context.omit = true, + "reset" => { + context.color = None; + context.omit = false; + }, + _ if command.trim().starts_with("color ") => { + let color = command["color ".len()..].trim(); + + let color = match color { + "normal" => DisplayColor::Normal, + "red" => DisplayColor::Red, + "orange" => DisplayColor::Orange, + "yellow" => DisplayColor::Yellow, + "green" => DisplayColor::Green, + "blue" => DisplayColor::Blue, + "Indigo" => DisplayColor::Indigo, + "Violet" => DisplayColor::Violet, + "Cycle" => DisplayColor::Cycle, + _ => DisplayColor::Normal, + }; + + context.color = Some(color); + }, + _ => () + } + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..e9410b396d3ccf47b4f8d6ed42f2eab7a7a52678 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,89 @@ +pub mod file_parser; +pub mod display_elements; +pub mod tcl_generator; + +use std::{path::PathBuf, fs::File, io::Write}; + +use clap::{arg, Parser}; +use file_parser::FileParser; +use glob::glob; +use tcl_generator::TclGenerator; +use vhdl_lang::{syntax::Symbols, Source}; + +use crate::display_elements::{Signal, DisplayOption, DisplayColor}; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + #[arg(short = 'f', long = "folder")] + folder: PathBuf, + #[arg(short = 't', long = "testbench")] + testbench: String, + #[arg(short = 'o', long = "output")] + output: PathBuf, +} + +fn main() { + let cli = Cli::parse(); + let find_wildcard = cli.folder.to_str().unwrap().to_owned() + "/**/*.vhd"; + println!("Going to look into {find_wildcard}"); + + let matching_files = glob(&find_wildcard).unwrap(); + + let symbols = Symbols::default(); + + let mut found = false; + for file_result in matching_files { + let file = file_result.unwrap(); + + let source = Source::from_latin1_file(file.as_path()).unwrap(); + let contents = source.contents(); + let mut parser = FileParser::new(&source, &contents, &symbols); + + match parser.find_next_entity() { + Ok(entity) => { + if entity.name() != &cli.testbench[..] { + continue; + } + found = true; + + println!("Found the testbench."); + + let entity = parser.parse_entity_architecture(entity).unwrap(); + let architecture = entity.architecture().unwrap(); + + let mut generator = TclGenerator::new("top.".to_owned() + &cli.testbench + "."); + generator.add_signal(&Signal::new("clk".to_owned(), vec![DisplayOption::Color(DisplayColor::Indigo)])) + .add_signal(&Signal::new("rst".to_owned(), vec![DisplayOption::Color(DisplayColor::Indigo)])) + .add_empty() + .zoom_out(); + + for signal in architecture.signals() { + if signal.name() == "clk" || signal.name() == "rst" { + continue; + } + + generator.add_signal(signal); + } + + let generated = generator.generate(); + + let mut file = File::create(&cli.output).unwrap(); + file.write_all(generated.as_bytes()).unwrap(); + + break; + }, + Err(err) => { + println!("{:?}", err); + } + } + + if found { + break; + } + } + + if !found { + println!("Could not find the entity.") + } +} diff --git a/src/tcl_generator.rs b/src/tcl_generator.rs new file mode 100644 index 0000000000000000000000000000000000000000..07fdb76c4da5cf76653358a2391a0561a16ff88e --- /dev/null +++ b/src/tcl_generator.rs @@ -0,0 +1,93 @@ +use string_builder::Builder; + +use crate::display_elements::{DisplayColor, DisplayFormat, Signal, DisplayOption}; + + +pub struct TclGenerator { + signals: Vec<(String, Option, Option)>, + zoom_out: bool, + signal_prefix: String, +} + +impl TclGenerator { + pub fn new(signal_prefix: String) -> Self { + Self { + signals: vec![], + zoom_out: false, + signal_prefix, + } + } + + pub fn add_signal(&mut self, signal: &Signal) -> &mut Self { + let mut color = None; + let mut format = None; + + for option in signal.options() { + match option { + DisplayOption::Omit => return self, + DisplayOption::Color(c) => { + color = Some(c.clone()); + }, + DisplayOption::Format(f) => { + format = Some(f.clone()); + } + } + } + + self.signals.push((signal.name().to_owned(), color, format)); + self + } + + pub fn add_empty(&mut self) -> &mut Self { + self.signals.push(("".to_owned(), None, None)); + self + } + + pub fn zoom_out(&mut self) -> &mut Self { + self.zoom_out = true; + self + } + + pub fn generate(self) -> String { + let mut builder = Builder::new(300); + + builder.append("gtkwave::nop\n"); + builder.append("gtkwave::/Edit/Set_Trace_Max_Hier 2\n"); + builder.append("gtkwave::/View/Show_Filled_High_Values 1\n"); + builder.append("gtkwave::/View/Show_Wave_Highlight 1\n"); + builder.append("gtkwave::/View/Show_Mouseover 1\n"); + builder.append("gtkwave::/View/Left_Justified_Signals 1\n"); + + for signal in self.signals { + if signal.0 == "" { + builder.append("gtkwave::/Edit/Insert_Blank\n"); + } else { + builder.append("gtkwave::addSignalsFromList \""); + builder.append(&self.signal_prefix[..]); + builder.append(&signal.0[..]); + builder.append("\"\n"); + + builder.append("gtkwave::highlightSignalsFromList \""); + builder.append(&self.signal_prefix[..]); + builder.append(&signal.0[..]); + builder.append("\"\n"); + + if let Some(color) = signal.1 { + builder.append(format!("gtkwave::/Edit/Color_Format/{color}\n")); + } + + if let Some(format) = signal.2 { + builder.append(format!("gtkwave::/Edit/Data_Format/{format}\n")); + } + + builder.append("gtkwave::/Edit/UnHighlight_All\n"); + } + } + + if self.zoom_out { + builder.append("gtkwave::/Time/Zoom/Zoom_Best_Fit\n"); + } + + builder.string().unwrap() + } +}