diff --git a/Cargo.lock b/Cargo.lock index 474a74df..860f9b1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -56,6 +44,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "0.6.18" @@ -115,12 +109,6 @@ dependencies = [ "backtrace", ] -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - [[package]] name = "autocfg" version = "1.4.0" @@ -225,6 +213,12 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.12" @@ -242,6 +236,33 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.5.28" @@ -341,7 +362,7 @@ dependencies = [ "codegen-sdk-cst", "codegen-sdk-cst-generator", "codegen-sdk-ts_query", - "convert_case 0.7.1", + "convert_case", "derive_more", "insta", "log", @@ -362,11 +383,14 @@ dependencies = [ "base64", "buildid", "bytes", - "convert_case 0.7.1", + "convert_case", + "indextree", "lazy_static", "mockall", "phf", "prettyplease", + "proc-macro2", + "quote", "rkyv", "salsa", "serde", @@ -374,7 +398,7 @@ dependencies = [ "sha2", "syn 2.0.98", "test-log", - "thiserror", + "thiserror 2.0.11", "tree-sitter", "tree-sitter-go", "tree-sitter-java", @@ -403,11 +427,14 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-resolution", "codegen-sdk-typescript", + "criterion", "env_logger", + "git2", "log", "rkyv", "salsa", "sysinfo", + "tempfile", "test-log", ] @@ -417,13 +444,14 @@ version = "0.1.0" dependencies = [ "bytes", "codegen-sdk-common", - "convert_case 0.7.1", + "convert_case", "dashmap", "log", "rkyv", "salsa", "tempfile", "test-log", + "thiserror 2.0.11", "tree-sitter", ] @@ -456,9 +484,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -476,9 +504,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -496,9 +524,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -516,9 +544,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -537,9 +565,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -566,9 +594,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -587,9 +615,9 @@ dependencies = [ "codegen-sdk-cst", "codegen-sdk-cst-generator", "codegen-sdk-resolution", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -616,9 +644,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -636,9 +664,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -656,9 +684,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -674,9 +702,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -694,9 +722,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -714,9 +742,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -736,9 +764,9 @@ dependencies = [ "codegen-sdk-common", "codegen-sdk-cst", "codegen-sdk-cst-generator", - "derive_generic_visitor", "derive_more", "env_logger", + "indextree", "log", "salsa", "subenum", @@ -764,15 +792,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "convert_case" version = "0.7.1" @@ -797,6 +816,42 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + [[package]] name = "crossbeam-channel" version = "0.5.14" @@ -840,6 +895,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + [[package]] name = "crypto-common" version = "0.1.6" @@ -850,41 +911,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.98", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.98", -] - [[package]] name = "dashmap" version = "6.1.0" @@ -899,29 +925,6 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "derive_generic_visitor" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e1c241e4f464b614bd7650f1a7c4c0e20e5ef21564d6b916b4c51fd76f7688" -dependencies = [ - "derive_generic_visitor_macros", -] - -[[package]] -name = "derive_generic_visitor_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885f5274163b5b1720591c0c24b34350a0b05e4774351f9fb3d13c192d8c995b" -dependencies = [ - "convert_case 0.6.0", - "darling", - "itertools 0.13.0", - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "derive_more" version = "2.0.1" @@ -953,6 +956,17 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "downcast" version = "0.11.0" @@ -1029,10 +1043,19 @@ dependencies = [ ] [[package]] -name = "fnv" -version = "1.0.7" +name = "foldhash" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] [[package]] name = "fragile" @@ -1133,35 +1156,61 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "git2" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fda788993cc341f69012feba8bf45c0ba4f3291fcc08e214b4d5a7332d88aff" +dependencies = [ + "bitflags 2.8.0", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + [[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "hashlink" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] @@ -1176,6 +1225,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "humantime" version = "2.1.0" @@ -1183,10 +1238,143 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] -name = "ident_case" -version = "1.0.1" +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] [[package]] name = "indexmap" @@ -1198,6 +1386,30 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "indextree" +version = "4.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91f3e68a01402c3404bfb739079f38858325bc7ad775b07922278a8a415b1a3f" +dependencies = [ + "indextree-macros", +] + +[[package]] +name = "indextree-macros" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "477e2e7ec7379407656293ff74902caea786a1dda427ca1f84b923c4fdeb7659" +dependencies = [ + "either", + "itertools 0.13.0", + "proc-macro2", + "quote", + "strum", + "syn 2.0.98", + "thiserror 1.0.69", +] + [[package]] name = "indicatif" version = "0.17.11" @@ -1255,6 +1467,17 @@ dependencies = [ "similar", ] +[[package]] +name = "is-terminal" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1336,6 +1559,20 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +[[package]] +name = "libgit2-sys" +version = "0.18.0+1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a117465e7e1597e8febea8bb0c410f1c7fb93b1e1cddf34363f8390367ffec" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + [[package]] name = "libredox" version = "0.1.3" @@ -1347,6 +1584,32 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1359,6 +1622,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + [[package]] name = "lock_api" version = "0.4.12" @@ -1540,6 +1809,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -1561,6 +1839,30 @@ version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "overload" version = "0.1.1" @@ -1590,6 +1892,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "phf" version = "0.11.3" @@ -1670,6 +1978,34 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "portable-atomic" version = "1.11.0" @@ -1980,14 +2316,12 @@ checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "salsa" version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e59d074084ce0a89693f021d8317cbc53d23d6502d3b3e2a3d1a7db1ceb13b" +source = "git+https://github.com/salsa-rs/salsa?branch=master#ceb9b083b3c0f6a1634e5a0b75b7bb5c7ca7b33f" dependencies = [ - "arc-swap", "boxcar", "crossbeam-queue", "dashmap", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "hashlink", "indexmap", "parking_lot", @@ -2001,15 +2335,13 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e354e0bdf1a23d822161e2b0f95c07846535a0e81deba77248a6ac22d19bc97" +version = "0.18.0" +source = "git+https://github.com/salsa-rs/salsa?branch=master#ceb9b083b3c0f6a1634e5a0b75b7bb5c7ca7b33f" [[package]] name = "salsa-macros" version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b061c51d6c6d5d8e4459bcaa11ef18d268286c68263615d65e983071b357fd9" +source = "git+https://github.com/salsa-rs/salsa?branch=master#ceb9b083b3c0f6a1634e5a0b75b7bb5c7ca7b33f" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2137,6 +2469,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "streaming-iterator" version = "0.1.9" @@ -2149,6 +2487,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.98", +] + [[package]] name = "subenum" version = "1.1.2" @@ -2249,13 +2609,33 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.11", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -2279,6 +2659,26 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.8.1" @@ -2540,6 +2940,29 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -2558,6 +2981,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -2597,6 +3026,7 @@ checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] @@ -2646,6 +3076,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web-time" version = "1.1.0" @@ -2904,6 +3344,18 @@ dependencies = [ "bitflags 2.8.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "xdg" version = "2.5.2" @@ -2911,19 +3363,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] -name = "zerocopy" -version = "0.7.35" +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ - "zerocopy-derive", + "yoke", + "zerofrom", + "zerovec-derive", ] [[package]] -name = "zerocopy-derive" -version = "0.7.35" +name = "zerovec-derive" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index e759856c..f42a448c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,9 @@ stable = ["json", "toml", "typescript", "tsx", "jsx", "go", "python", "yaml", "j default = [] [dev-dependencies] test-log = { workspace = true } +criterion = { version = "0.5", features = ["html_reports"] } +git2 = { version = "0.20.0" } +tempfile = {workspace = true} [workspace] members = [ "codegen-sdk-analyzer", @@ -109,40 +112,48 @@ codegen-sdk-json = { path = "languages/codegen-sdk-json" } tempfile = "3.16.0" quote = "1.0.38" proc-macro2 = "1.0.93" -derive_generic_visitor = "0.1.1" insta = "1.42.1" prettyplease = "0.2.29" -syn = { version = "2.0.98", features = ["proc-macro"] } +syn = { version = "2.0.98", features = ["proc-macro", "full"] } derive_more = { version = "2.0.1", features = ["debug", "display"] } -salsa = "0.18.0" +salsa = {git = "https://github.com/salsa-rs/salsa", branch = "master"} subenum = {git = "https://github.com/mrenow/subenum", branch = "main"} indicatif-log-bridge = "0.2.3" indicatif = { version = "0.17.11", features = ["rayon"] } crossbeam-channel = "0.5.11" rstest = "0.25.0" +indextree = "4.7.3" +thiserror = "2.0.11" + [profile.dev] # codegen-backend = "cranelift" -split-debuginfo = "unpacked" +# split-debuginfo = "unpacked" [profile.dev.package] insta.opt-level = 3 similar.opt-level = 3 syn.opt-level = 3 convert_case.opt-level = 3 -codegen-sdk-cst-generator.opt-level = 3 -codegen-sdk-common.opt-level = 3 +# codegen-sdk-cst-generator.opt-level = 3 +# codegen-sdk-common.opt-level = 3 [profile.dev.build-override] opt-level = 3 +debug = true -[profile.test.package."codegen-sdk-cst"] -inherits = "dev" -opt-level = 0 -debug = 0 -strip = "none" -codegen-units = 256 -incremental = true +# [profile.test.package."codegen-sdk-cst"] +# inherits = "dev" +# opt-level = 0 +# debug = 0 +# strip = "none" +# codegen-units = 256 +# incremental = true # codegen-backend = "cranelift" [profile.test] lto = false + +[[bench]] +name = "parse" +harness = false +required-features = ["stable"] diff --git a/benches/parse.rs b/benches/parse.rs new file mode 100644 index 00000000..dea5c0bb --- /dev/null +++ b/benches/parse.rs @@ -0,0 +1,36 @@ +use std::{hint::black_box, path::PathBuf}; + +use codegen_sdk_analyzer::Codebase; +use criterion::{Criterion, criterion_group, criterion_main}; +fn clone_repo(url: String, name: String, tmp_dir: &tempfile::TempDir) -> PathBuf { + let repo_path = tmp_dir.path().join(name); + if !repo_path.exists() { + log::info!("Cloning repo: {} to {}", url, repo_path.display()); + let mut fetch_opts = git2::FetchOptions::new(); + fetch_opts.depth(1); + let _ = git2::build::RepoBuilder::new() + .fetch_options(fetch_opts) + .clone(&url, &repo_path) + .unwrap(); + } + repo_path +} +fn parse_nest(path: &PathBuf) { + let _ = Codebase::new(path.clone()); +} + +fn criterion_benchmark(c: &mut Criterion) { + env_logger::init(); + let temp_dir = tempfile::tempdir().unwrap(); + let repo_path = clone_repo( + "https://github.com/nestjs/nest".to_string(), + "nest".to_string(), + &temp_dir, + ); + c.bench_function("parse_nest", |b| { + b.iter(|| parse_nest(black_box(&repo_path))) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/codegen-sdk-analyzer/src/codebase/discovery.rs b/codegen-sdk-analyzer/src/codebase/discovery.rs index 9c2a7b4b..825a5086 100644 --- a/codegen-sdk-analyzer/src/codebase/discovery.rs +++ b/codegen-sdk-analyzer/src/codebase/discovery.rs @@ -22,14 +22,15 @@ pub fn log_languages() { pub fn collect_files(db: &CodegenDatabase, dir: &PathBuf) -> FilesToParse { let mut files = Vec::new(); + let dir = dir.canonicalize().unwrap(); for language in LANGUAGES.iter() { for extension in language.file_extensions.iter() { files.extend( - glob(&format!( - "{dir}**/*.{extension}", - extension = extension, - dir = dir.display() - )) + glob( + &dir.join(format!("**/*.{extension}", extension = extension)) + .to_str() + .unwrap(), + ) .unwrap(), ); } diff --git a/codegen-sdk-analyzer/src/parser.rs b/codegen-sdk-analyzer/src/parser.rs index fae30f85..b3cf807b 100644 --- a/codegen-sdk-analyzer/src/parser.rs +++ b/codegen-sdk-analyzer/src/parser.rs @@ -1,5 +1,4 @@ -use std::path::PathBuf; - +use codegen_sdk_common::FileNodeId; use codegen_sdk_cst::CSTLanguage; use codegen_sdk_macros::{languages_ast, parse_language}; languages_ast!(); @@ -7,12 +6,13 @@ languages_ast!(); #[salsa::tracked] pub struct Parsed<'db> { #[id] - path: PathBuf, + path: FileNodeId<'db>, #[return_ref] + #[tracked] pub file: Option>, } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn parse_file(db: &dyn salsa::Database, file: codegen_sdk_ast::input::File) -> Parsed<'_> { parse_language!(); - Parsed::new(db, file.path(db), None) + Parsed::new(db, FileNodeId::new(db, file.path(db)), None) } diff --git a/codegen-sdk-ast-generator/src/generator.rs b/codegen-sdk-ast-generator/src/generator.rs index fe0df99c..0b8bf1e6 100644 --- a/codegen-sdk-ast-generator/src/generator.rs +++ b/codegen-sdk-ast-generator/src/generator.rs @@ -8,8 +8,8 @@ fn get_definitions_impl(language: &Language) -> TokenStream { impl<'db> codegen_sdk_ast::Definitions<'db> for #language_struct_name<'db> { type Definitions = (); - fn definitions(self, _db: &'db dyn salsa::Database) -> Self::Definitions{ - () + fn definitions(self, _db: &'db dyn salsa::Database) -> &'db Self::Definitions{ + &() } } }; @@ -18,13 +18,13 @@ fn get_definitions_impl(language: &Language) -> TokenStream { #[salsa::tracked] impl<'db> codegen_sdk_ast::Definitions<'db> for #language_struct_name<'db> { type Definitions = Definitions<'db>; - #[salsa::tracked] + #[salsa::tracked(return_ref)] fn definitions(self, db: &'db dyn salsa::Database) -> Self::Definitions { - let mut definitions = Definitions::default(); if let Some(program) = self.node(db) { - definitions = definitions.visit_by_val_infallible(&program); + return Definitions::visit(db, program); + } else { + return Definitions::default(db); } - definitions } } } @@ -35,8 +35,8 @@ fn get_references_impl(language: &Language) -> TokenStream { return quote! { impl<'db> codegen_sdk_ast::References<'db> for #language_struct_name<'db> { type References = (); - fn references(self, _db: &'db dyn salsa::Database) -> Self::References { - () + fn references(self, _db: &'db dyn salsa::Database) -> &'db Self::References { + &() } } }; @@ -45,13 +45,13 @@ fn get_references_impl(language: &Language) -> TokenStream { #[salsa::tracked] impl<'db> codegen_sdk_ast::References<'db> for #language_struct_name<'db> { type References = References<'db>; - #[salsa::tracked] + #[salsa::tracked(return_ref)] fn references(self, db: &'db dyn salsa::Database) -> Self::References { - let mut references = References::default(); - if let Some(program) = self.node(db) { - references = references.visit_by_val_infallible(&program); - } - references + if let Some(program) = self.node(db) { + return References::visit(db, program); + } else { + return References::default(db); + } } } } @@ -61,14 +61,15 @@ pub fn generate_ast(language: &Language) -> anyhow::Result { let language_name_str = language.name(); let definitions_impl = get_definitions_impl(language); let references_impl = get_references_impl(language); - let program_id = format_ident!("{}", language.root_node()); + let root_node_name = format_ident!("{}", language.root_node()); let content = quote! { #[salsa::tracked] pub struct #language_struct_name<'db> { + #[tracked] #[return_ref] - node: Option>, + pub node: Option>, #[id] - pub path: PathBuf, + pub id: codegen_sdk_common::FileNodeId<'db>, } // impl<'db> File for {language_struct_name}File<'db> {{ // fn path(&self) -> &PathBuf {{ @@ -77,15 +78,24 @@ pub fn generate_ast(language: &Language) -> anyhow::Result { // }} pub fn parse(db: &dyn salsa::Database, input: codegen_sdk_ast::input::File) -> #language_struct_name<'_> { log::debug!("Parsing {} file: {}", input.path(db).display(), #language_name_str); - let ast = crate::cst::parse_program_raw(db, input.contents(db)); - #language_struct_name::new(db, ast, input.path(db).clone()) + let ast = crate::cst::parse_program_raw(db, input.contents(db), input.path(db).clone()); + let file_id = codegen_sdk_common::FileNodeId::new(db, input.path(db).clone()); + #language_struct_name::new(db, ast, file_id) } - #[salsa::tracked] + #[salsa::tracked(return_ref)] pub fn parse_query(db: &dyn salsa::Database, input: codegen_sdk_ast::input::File) -> #language_struct_name<'_> { parse(db, input) } - + impl<'db> #language_struct_name<'db> { + pub fn tree(&self, db: &'db dyn salsa::Database) -> &'db codegen_sdk_common::Tree> { + self.node(db).unwrap().tree(db) + } + pub fn root(&self, db: &'db dyn salsa::Database) -> &'db crate::cst::#root_node_name<'db> { + let tree = self.tree(db); + tree.get(&self.node(db).unwrap().program(db)).unwrap().as_ref().try_into().unwrap() + } + } #definitions_impl #references_impl // impl<'db> HasNode for {language_struct_name}File<'db> { diff --git a/codegen-sdk-ast-generator/src/lib.rs b/codegen-sdk-ast-generator/src/lib.rs index c0f50c63..4e92edec 100644 --- a/codegen-sdk-ast-generator/src/lib.rs +++ b/codegen-sdk-ast-generator/src/lib.rs @@ -10,11 +10,11 @@ use syn::parse_quote; pub fn generate_ast(language: &Language) -> anyhow::Result<()> { let db = CSTDatabase::default(); let imports = quote! { - use derive_generic_visitor::{Visitor, Drive, Visit}; use codegen_sdk_common::*; use std::path::PathBuf; use codegen_sdk_cst::CSTLanguage; use std::collections::BTreeMap; + use std::sync::mpsc::Sender; }; let ast = generator::generate_ast(language)?; let definition_visitor = visitor::generate_visitor(&db, language, "definition"); diff --git a/codegen-sdk-ast-generator/src/query.rs b/codegen-sdk-ast-generator/src/query.rs index db2664f7..319344d3 100644 --- a/codegen-sdk-ast-generator/src/query.rs +++ b/codegen-sdk-ast-generator/src/query.rs @@ -1,7 +1,7 @@ use std::{collections::BTreeMap, sync::Arc}; use codegen_sdk_common::{ - CSTNode, HasChildren, Language, + CSTNode, HasChildren, Language, Tree, naming::{normalize_field_name, normalize_type_name}, }; use codegen_sdk_cst::CSTLanguage; @@ -11,17 +11,19 @@ use derive_more::Debug; use log::{debug, info, warn}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; +use ts_query::NodeTypes; fn captures_for_field_definition<'a>( - node: &ts_query::FieldDefinition<'a>, -) -> impl Iterator> { + node: &'a ts_query::FieldDefinition<'a>, + tree: &'a Tree>, +) -> impl Iterator> { let mut captures = Vec::new(); - for child in node.children() { + for child in node.children(tree) { match child { - ts_query::FieldDefinitionChildren::NamedNode(named) => { - captures.extend(captures_for_named_node(&named)); + ts_query::FieldDefinitionChildrenRef::NamedNode(named) => { + captures.extend(captures_for_named_node(&named, tree)); } - ts_query::FieldDefinitionChildren::FieldDefinition(field) => { - captures.extend(captures_for_field_definition(&field)); + ts_query::FieldDefinitionChildrenRef::FieldDefinition(field) => { + captures.extend(captures_for_field_definition(&field, tree)); } _ => {} } @@ -29,17 +31,18 @@ fn captures_for_field_definition<'a>( captures.into_iter() } fn captures_for_named_node<'a>( - node: &ts_query::NamedNode<'a>, -) -> impl Iterator> { + node: &'a ts_query::NamedNode<'a>, + tree: &'a Tree>, +) -> impl Iterator> { let mut captures = Vec::new(); - for child in node.children() { + for child in node.children(tree) { match child { - ts_query::NamedNodeChildren::Capture(capture) => captures.push(capture), - ts_query::NamedNodeChildren::NamedNode(named) => { - captures.extend(captures_for_named_node(&named)); + ts_query::NamedNodeChildrenRef::Capture(capture) => captures.push(capture), + ts_query::NamedNodeChildrenRef::NamedNode(named) => { + captures.extend(captures_for_named_node(&named, tree)); } - ts_query::NamedNodeChildren::FieldDefinition(field) => { - captures.extend(captures_for_field_definition(&field)); + ts_query::NamedNodeChildrenRef::FieldDefinition(field) => { + captures.extend(captures_for_field_definition(&field, tree)); } _ => {} } @@ -48,8 +51,9 @@ fn captures_for_named_node<'a>( } #[derive(Debug)] pub struct Query<'a> { - node: ts_query::NamedNode<'a>, + node: &'a ts_query::NamedNode<'a>, language: &'a Language, + tree: &'a Tree>, pub(crate) state: Arc>, } impl<'a> Query<'a> { @@ -58,22 +62,21 @@ impl<'a> Query<'a> { source: &str, language: &'a Language, ) -> BTreeMap { - let parsed = ts_query::Query::parse(db, source.to_string()) - .as_ref() - .unwrap(); + let result = ts_query::Query::parse(db, source.to_string()).unwrap(); + let (parsed, tree) = result; let config = Config::default(); let state = Arc::new(State::new(language, config)); let mut queries = BTreeMap::new(); - for node in parsed.children() { + for node in parsed.children(tree) { match node { - ts_query::ProgramChildren::NamedNode(named) => { - let query = Self::from_named_node(&named, language, state.clone()); + ts_query::ProgramChildrenRef::NamedNode(named) => { + let query = Self::from_named_node(&named, language, state.clone(), tree); queries.insert(query.name(), query); } node => { log::warn!( "Unhandled query: {:#?}. Source: {:#?}", - node.kind(), + node.kind_name(), node.source() ); } @@ -95,19 +98,21 @@ impl<'a> Query<'a> { queries } fn from_named_node( - named: &ts_query::NamedNode<'a>, + named: &'a ts_query::NamedNode<'a>, language: &'a Language, state: Arc>, + tree: &'a Tree>, ) -> Self { Query { - node: named.clone(), + node: named, language: language, state: state, + tree: tree, } } /// Get the kind of the query (the node to be matched) pub fn kind(&self) -> String { - if let ts_query::NamedNodeName::Identifier(identifier) = &(*self.node.name) { + if let ts_query::NamedNodeNameRef::Identifier(identifier) = self.node.name(self.tree) { return identifier.source(); } panic!("No kind found for query. {:#?}", self.node); @@ -124,15 +129,15 @@ impl<'a> Query<'a> { return vec![self.struct_name()]; } self.state - .get_variants(&self.struct_name()) + .get_variants(&self.struct_name(), false) .into_iter() .map(|v| v.normalize()) .filter(|v| v != "Comment") .collect() } - fn captures(&self) -> Vec { - captures_for_named_node(&self.node).collect() + fn captures(&self) -> Vec<&ts_query::Capture> { + captures_for_named_node(&self.node, self.tree).collect() } /// Get the name of the query (IE @reference.class) pub fn name(&self) -> String { @@ -205,10 +210,15 @@ impl<'a> Query<'a> { current_node: &Ident, name_value: Option, ) -> TokenStream { - let other_child: ts_query::NodeTypes = - field.children().into_iter().skip(2).next().unwrap().into(); - for name in &field.name { - if let ts_query::FieldDefinitionName::Identifier(identifier) = name { + let other_child: ts_query::NodeTypesRef = field + .children(self.tree) + .into_iter() + .skip(2) + .next() + .unwrap() + .into(); + for name in &field.name(self.tree) { + if let ts_query::FieldDefinitionNameRef::Identifier(identifier) = name { let name = normalize_field_name(&identifier.source()); if let Some(field) = self.get_field_for_field_name(&name, struct_name) { let field_name = format_ident!("{}", name); @@ -228,12 +238,12 @@ impl<'a> Query<'a> { // ); if !field.is_optional() { return quote! { - let #field_name = &*#current_node.#field_name; + let #field_name = #current_node.#field_name(tree); #wrapped }; } else { return quote! { - if let Some(#field_name) = &*#current_node.#field_name { + if let Some(#field_name) = #current_node.#field_name(tree) { #wrapped } }; @@ -263,7 +273,7 @@ impl<'a> Query<'a> { name_value: Option, ) -> TokenStream { let mut matchers = TokenStream::new(); - for group in node.children() { + for group in node.children(self.tree) { let result = self.get_matcher_for_definition( struct_name, group.into(), @@ -280,13 +290,15 @@ impl<'a> Query<'a> { target_name: &str, target_kind: &str, current_node: &Ident, - remaining_nodes: Vec>, + remaining_nodes: Vec>, name_value: Option, ) -> TokenStream { let mut matchers = TokenStream::new(); let mut field_matchers = TokenStream::new(); let mut comment_variant = None; - let variants = self.state.get_variants(&format!("{}Children", target_kind)); + let variants = self + .state + .get_variants(&format!("{}Children", target_kind), true); if variants.len() == 2 { if variants.iter().any(|v| v.normalize() == "Comment") { for variant in variants { @@ -299,7 +311,7 @@ impl<'a> Query<'a> { } for child in remaining_nodes { - if child.kind() == "field_definition" { + if child.kind_name() == "field_definition" { field_matchers.extend_one(self.get_matcher_for_definition( &target_name, child.into(), @@ -316,9 +328,8 @@ impl<'a> Query<'a> { if let Some(ref variant) = comment_variant { let children = format_ident!("{}Children", target_name); - let variant = format_ident!("{}", variant); + let variant = format_ident!("{}Ref", variant); matchers.extend_one(quote! { - if let crate::cst::#children::#variant(#current_node) = #current_node { #result } @@ -334,7 +345,7 @@ impl<'a> Query<'a> { quote! {} } else { quote! { - for child in #current_node.children().into_iter() { + for child in #current_node.children(tree) { #matchers break; } @@ -355,9 +366,9 @@ impl<'a> Query<'a> { if struct_name == target_name { return base_matcher; } else { - let mut children = format_ident!("{}", struct_name); + let mut children = format_ident!("{}Ref", struct_name); if let Some(node) = self.state.get_node_for_struct_name(struct_name) { - children = format_ident!("{}", node.children_struct_name()); + children = format_ident!("{}Ref", node.children_struct_name()); } let variant = format_ident!("{}", target_name); return quote! { @@ -368,26 +379,26 @@ impl<'a> Query<'a> { } } fn group_children<'b>( - &self, - node: &ts_query::NamedNode<'b>, - first_node: &ts_query::NamedNodeChildren<'_>, + &'b self, + node: &'b ts_query::NamedNode<'b>, + first_node: &ts_query::NamedNodeChildrenRef<'_>, mut name_value: Option, current_node: &Ident, - ) -> (Option, Vec>) { + ) -> (Option, Vec>) { let mut prev = first_node.clone(); let mut remaining_nodes = Vec::new(); - for child in node.children().into_iter().skip(1) { - if child.kind() == "capture" { + for child in node.children(self.tree).into_iter().skip(1) { + if child.kind_name() == "capture" { if child.source() == "@name" { log::info!( "Found @name! prev: {:#?}, {:#?}", prev.source(), - prev.kind() + prev.kind_name() ); match prev { - ts_query::NamedNodeChildren::FieldDefinition(field) => { + ts_query::NamedNodeChildrenRef::FieldDefinition(field) => { let field_name = field - .name + .name(self.tree) .iter() .filter(|c| c.is_named()) .map(|c| format_ident!("{}", c.source())) @@ -397,24 +408,24 @@ impl<'a> Query<'a> { #current_node.#field_name.source() }); } - ts_query::NamedNodeChildren::Identifier(named) => { + ts_query::NamedNodeChildrenRef::Identifier(named) => { log::info!( "Found @name! prev: {:#?}, {:#?}", named.source(), - named.kind() + named.kind_name() ); name_value = Some(quote! { #current_node.source() }); } - ts_query::NamedNodeChildren::AnonymousUnderscore(_) => { + ts_query::NamedNodeChildrenRef::AnonymousUnderscore(_) => { name_value = Some(quote! { #current_node.source() }); } _ => panic!( "Unexpected prev: {:#?}, source: {:#?}. Query: {:#?}", - prev.kind(), + prev.kind_name(), prev.source(), self.node().source() ), @@ -436,7 +447,7 @@ impl<'a> Query<'a> { name_value: Option, ) -> TokenStream { let mut matchers = TokenStream::new(); - let first_node = node.children().into_iter().next().unwrap(); + let first_node = node.children(self.tree).into_iter().next().unwrap(); let (name_value, remaining_nodes) = self.group_children(node, &first_node, name_value, current_node); if remaining_nodes.len() == 0 { @@ -491,9 +502,7 @@ impl<'a> Query<'a> { let to_append = self.executor_id(); if let Some(name_value) = name_value { return quote! { - self.#to_append.entry(#name_value).or_insert(Vec::new()).push( - node.clone() - ); + #to_append.entry(#name_value).or_default().push(id); }; } log::warn!("No name value found for: {}", self.node().source()); @@ -508,35 +517,35 @@ impl<'a> Query<'a> { ) -> TokenStream { // We have 2 nodes, the parent node and the identifier node let to_append = self.get_default_matcher(name_value); - let children; // Case 1: The identifier is the same as the struct name (IE: we know this is the corrent node) if normalize_type_name(&identifier.source(), true) == struct_name { return to_append; } // Case 2: We have a node for the parent struct if let Some(node) = self.state.get_node_for_struct_name(struct_name) { - children = format_ident!("{}Children", struct_name); + let mut children = format_ident!("{}Children", struct_name); // When there is only 1 possible child, we can use the default matcher if node.children_struct_name() != children.to_string() { return to_append; } + children = format_ident!("{}ChildrenRef", struct_name); + let struct_name = format_ident!("{}", normalize_type_name(&identifier.source(), true)); + quote! { + if let crate::cst::#children::#struct_name(child) = #current_node { + #to_append + } + + } } else { // Case 3: This is a subenum // If this is a field, we may be dealing with multiple types and can't operate over all of them return to_append; // TODO: Handle this case } - let struct_name = format_ident!("{}", normalize_type_name(&identifier.source(), true)); - quote! { - if let crate::cst::#children::#struct_name(child) = #current_node { - #to_append - } - - } } fn get_matcher_for_definition( &self, struct_name: &str, - node: ts_query::NodeTypes, + node: ts_query::NodeTypesRef, current_node: &Ident, name_value: Option, ) -> TokenStream { @@ -544,21 +553,21 @@ impl<'a> Query<'a> { return self.get_default_matcher(name_value); } match node { - ts_query::NodeTypes::FieldDefinition(field) => { + ts_query::NodeTypesRef::FieldDefinition(field) => { self.get_matcher_for_field(&field, struct_name, current_node, name_value) } - ts_query::NodeTypes::Capture(named) => { + ts_query::NodeTypesRef::Capture(named) => { info!("Capture: {:#?}", named.source()); quote! {} } - ts_query::NodeTypes::NamedNode(named) => { + ts_query::NodeTypesRef::NamedNode(named) => { self.get_matcher_for_named_node(&named, struct_name, current_node, name_value) } - ts_query::NodeTypes::Comment(_) => { + ts_query::NodeTypesRef::Comment(_) => { quote! {} } - ts_query::NodeTypes::List(subenum) => { - for child in subenum.children() { + ts_query::NodeTypesRef::List(subenum) => { + for child in subenum.children(self.tree) { let result = self.get_matcher_for_definition( struct_name, child.into(), @@ -570,17 +579,17 @@ impl<'a> Query<'a> { } quote! {} } - ts_query::NodeTypes::Grouping(grouping) => { + ts_query::NodeTypesRef::Grouping(grouping) => { self.get_matchers_for_grouping(&grouping, struct_name, current_node, name_value) } - ts_query::NodeTypes::Identifier(identifier) => { + ts_query::NodeTypesRef::Identifier(identifier) => { self.get_matcher_for_identifier(&identifier, struct_name, current_node, name_value) } unhandled => { log::warn!( "Unhandled definition in language {}: {:#?}, {:#?}", self.language.name(), - unhandled.kind(), + unhandled.kind_name(), unhandled.source() ); self.get_default_matcher(name_value) @@ -598,7 +607,7 @@ impl<'a> Query<'a> { let starting_node = format_ident!("node"); let (name_value, remaining_nodes) = self.group_children( &self.node(), - &self.node().children().into_iter().next().unwrap(), + &self.node().children(self.tree).into_iter().next().unwrap(), None, &starting_node, ); diff --git a/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__python.snap b/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__python.snap index c2a1131b..f655a511 100644 --- a/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__python.snap +++ b/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__python.snap @@ -2,743 +2,114 @@ source: codegen-sdk-ast-generator/src/visitor.rs expression: "codegen_sdk_common::generator::format_code_string(&visitor.to_string()).unwrap()" --- -#[derive(Visitor, Visit, Debug, Clone, Eq, PartialEq, salsa::Update, Hash, Default)] -#[visit(drive(&crate::cst::AliasedImport<'db>))] -#[visit(drive(&crate::cst::AliasedImportChildren<'db>))] -#[visit(drive(&crate::cst::AnonymousAmpersand<'db>))] -#[visit(drive(&crate::cst::AnonymousAmpersandEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAnd<'db>))] -#[visit(drive(&crate::cst::AnonymousAs<'db>))] -#[visit(drive(&crate::cst::AnonymousAssert<'db>))] -#[visit(drive(&crate::cst::AnonymousAsterisk<'db>))] -#[visit(drive(&crate::cst::AnonymousAsteriskAsterisk<'db>))] -#[visit(drive(&crate::cst::AnonymousAsteriskAsteriskEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAsteriskEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAsync<'db>))] -#[visit(drive(&crate::cst::AnonymousAt<'db>))] -#[visit(drive(&crate::cst::AnonymousAtEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAwait<'db>))] -#[visit(drive(&crate::cst::AnonymousBackslash<'db>))] -#[visit(drive(&crate::cst::AnonymousBangEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousBreak<'db>))] -#[visit(drive(&crate::cst::AnonymousCaret<'db>))] -#[visit(drive(&crate::cst::AnonymousCaretEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousCase<'db>))] -#[visit(drive(&crate::cst::AnonymousClass<'db>))] -#[visit(drive(&crate::cst::AnonymousCloseBrace<'db>))] -#[visit(drive(&crate::cst::AnonymousCloseBracket<'db>))] -#[visit(drive(&crate::cst::AnonymousCloseParen<'db>))] -#[visit(drive(&crate::cst::AnonymousColon<'db>))] -#[visit(drive(&crate::cst::AnonymousColonEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousComma<'db>))] -#[visit(drive(&crate::cst::AnonymousContinue<'db>))] -#[visit(drive(&crate::cst::AnonymousDef<'db>))] -#[visit(drive(&crate::cst::AnonymousDel<'db>))] -#[visit(drive(&crate::cst::AnonymousDot<'db>))] -#[visit(drive(&crate::cst::AnonymousElif<'db>))] -#[visit(drive(&crate::cst::AnonymousElse<'db>))] -#[visit(drive(&crate::cst::AnonymousEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousEqualsEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousExcept<'db>))] -#[visit(drive(&crate::cst::AnonymousExceptAsterisk<'db>))] -#[visit(drive(&crate::cst::AnonymousExec<'db>))] -#[visit(drive(&crate::cst::AnonymousFinally<'db>))] -#[visit(drive(&crate::cst::AnonymousFor<'db>))] -#[visit(drive(&crate::cst::AnonymousFrom<'db>))] -#[visit(drive(&crate::cst::AnonymousFuture<'db>))] -#[visit(drive(&crate::cst::AnonymousGlobal<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanGreaterThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousIf<'db>))] -#[visit(drive(&crate::cst::AnonymousImport<'db>))] -#[visit(drive(&crate::cst::AnonymousIn<'db>))] -#[visit(drive(&crate::cst::AnonymousIs<'db>))] -#[visit(drive(&crate::cst::AnonymousIsNot<'db>))] -#[visit(drive(&crate::cst::AnonymousLambda<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThan<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThanGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThanLessThan<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThanLessThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousMatch<'db>))] -#[visit(drive(&crate::cst::AnonymousMinus<'db>))] -#[visit(drive(&crate::cst::AnonymousMinusEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousMinusGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousNonlocal<'db>))] -#[visit(drive(&crate::cst::AnonymousNot<'db>))] -#[visit(drive(&crate::cst::AnonymousNotIn<'db>))] -#[visit(drive(&crate::cst::AnonymousOpenBrace<'db>))] -#[visit(drive(&crate::cst::AnonymousOpenBracket<'db>))] -#[visit(drive(&crate::cst::AnonymousOpenParen<'db>))] -#[visit(drive(&crate::cst::AnonymousOr<'db>))] -#[visit(drive(&crate::cst::AnonymousPass<'db>))] -#[visit(drive(&crate::cst::AnonymousPercent<'db>))] -#[visit(drive(&crate::cst::AnonymousPercentEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousPipe<'db>))] -#[visit(drive(&crate::cst::AnonymousPipeEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousPlus<'db>))] -#[visit(drive(&crate::cst::AnonymousPlusEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousPrint<'db>))] -#[visit(drive(&crate::cst::AnonymousRaise<'db>))] -#[visit(drive(&crate::cst::AnonymousReturn<'db>))] -#[visit(drive(&crate::cst::AnonymousSemicolon<'db>))] -#[visit(drive(&crate::cst::AnonymousSlash<'db>))] -#[visit(drive(&crate::cst::AnonymousSlashEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousSlashSlash<'db>))] -#[visit(drive(&crate::cst::AnonymousSlashSlashEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousTilde<'db>))] -#[visit(drive(&crate::cst::AnonymousTry<'db>))] -#[visit(drive(&crate::cst::AnonymousType<'db>))] -#[visit(drive(&crate::cst::AnonymousUnderscore<'db>))] -#[visit(drive(&crate::cst::AnonymousWhile<'db>))] -#[visit(drive(&crate::cst::AnonymousWith<'db>))] -#[visit(drive(&crate::cst::AnonymousYield<'db>))] -#[visit(drive(&crate::cst::ArgumentList<'db>))] -#[visit(drive(&crate::cst::ArgumentListChildren<'db>))] -#[visit(drive(&crate::cst::AsPattern<'db>))] -#[visit(drive(&crate::cst::AsPatternChildren<'db>))] -#[visit(drive(&crate::cst::AsPatternTarget<'db>))] -#[visit(drive(&crate::cst::AssertStatement<'db>))] -#[visit(drive(&crate::cst::AssertStatementChildren<'db>))] -#[visit(drive(&crate::cst::Assignment<'db>))] -#[visit(drive(&crate::cst::AssignmentChildren<'db>))] -#[visit(drive(&crate::cst::AssignmentLeft<'db>))] -#[visit(drive(&crate::cst::AssignmentRight<'db>))] -#[visit(drive(&crate::cst::Attribute<'db>))] -#[visit(drive(&crate::cst::AttributeChildren<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignment<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentChildren<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentLeft<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentOperator<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentRight<'db>))] -#[visit(drive(&crate::cst::Await<'db>))] -#[visit(drive(&crate::cst::AwaitChildren<'db>))] -#[visit(drive(&crate::cst::BinaryOperator<'db>))] -#[visit(drive(&crate::cst::BinaryOperatorChildren<'db>))] -#[visit(drive(&crate::cst::BinaryOperatorOperator<'db>))] -#[visit(drive(&crate::cst::Block<'db>))] -#[visit(drive(&crate::cst::BlockChildren<'db>))] -#[visit(drive(&crate::cst::BooleanOperator<'db>))] -#[visit(drive(&crate::cst::BooleanOperatorChildren<'db>))] -#[visit(drive(&crate::cst::BooleanOperatorOperator<'db>))] -#[visit(drive(&crate::cst::BreakStatement<'db>))] -#[visit(drive(&crate::cst::Call<'db>))] -#[visit(drive(&crate::cst::CallArguments<'db>))] -#[visit(drive(&crate::cst::CallChildren<'db>))] -#[visit(drive(&crate::cst::CaseClause<'db>))] -#[visit(drive(&crate::cst::CaseClauseChildren<'db>))] -#[visit(drive(&crate::cst::CasePattern<'db>))] -#[visit(drive(&crate::cst::CasePatternChildren<'db>))] -#[visit(drive(&crate::cst::Chevron<'db>))] -#[visit(drive(&crate::cst::ChevronChildren<'db>))] -#[visit(drive(&crate::cst::ClassDefinitionChildren<'db>))] -#[visit(drive(&crate::cst::ClassPattern<'db>))] -#[visit(drive(&crate::cst::ClassPatternChildren<'db>))] -#[visit(drive(&crate::cst::Comment<'db>))] -#[visit(drive(&crate::cst::ComparisonOperator<'db>))] -#[visit(drive(&crate::cst::ComparisonOperatorChildren<'db>))] -#[visit(drive(&crate::cst::ComparisonOperatorOperators<'db>))] -#[visit(drive(&crate::cst::ComplexPattern<'db>))] -#[visit(drive(&crate::cst::ComplexPatternChildren<'db>))] -#[visit(drive(&crate::cst::CompoundStatement<'db>))] -#[visit(drive(&crate::cst::ConcatenatedString<'db>))] -#[visit(drive(&crate::cst::ConcatenatedStringChildren<'db>))] -#[visit(drive(&crate::cst::ConditionalExpression<'db>))] -#[visit(drive(&crate::cst::ConditionalExpressionChildren<'db>))] -#[visit(drive(&crate::cst::ConstrainedType<'db>))] -#[visit(drive(&crate::cst::ConstrainedTypeChildren<'db>))] -#[visit(drive(&crate::cst::ContinueStatement<'db>))] -#[visit(drive(&crate::cst::DecoratedDefinition<'db>))] -#[visit(drive(&crate::cst::DecoratedDefinitionChildren<'db>))] -#[visit(drive(&crate::cst::DecoratedDefinitionDefinition<'db>))] -#[visit(drive(&crate::cst::Decorator<'db>))] -#[visit(drive(&crate::cst::DecoratorChildren<'db>))] -#[visit(drive(&crate::cst::DefaultParameter<'db>))] -#[visit(drive(&crate::cst::DefaultParameterChildren<'db>))] -#[visit(drive(&crate::cst::DefaultParameterName<'db>))] -#[visit(drive(&crate::cst::DeleteStatement<'db>))] -#[visit(drive(&crate::cst::DeleteStatementChildren<'db>))] -#[visit(drive(&crate::cst::DictPattern<'db>))] -#[visit(drive(&crate::cst::DictPatternChildren<'db>))] -#[visit(drive(&crate::cst::DictPatternKey<'db>))] -#[visit(drive(&crate::cst::Dictionary<'db>))] -#[visit(drive(&crate::cst::DictionaryChildren<'db>))] -#[visit(drive(&crate::cst::DictionaryComprehension<'db>))] -#[visit(drive(&crate::cst::DictionaryComprehensionChildren<'db>))] -#[visit(drive(&crate::cst::DictionarySplat<'db>))] -#[visit(drive(&crate::cst::DictionarySplatChildren<'db>))] -#[visit(drive(&crate::cst::DictionarySplatPattern<'db>))] -#[visit(drive(&crate::cst::DictionarySplatPatternChildren<'db>))] -#[visit(drive(&crate::cst::DottedName<'db>))] -#[visit(drive(&crate::cst::DottedNameChildren<'db>))] -#[visit(drive(&crate::cst::ElifClause<'db>))] -#[visit(drive(&crate::cst::ElifClauseChildren<'db>))] -#[visit(drive(&crate::cst::Ellipsis<'db>))] -#[visit(drive(&crate::cst::ElseClause<'db>))] -#[visit(drive(&crate::cst::ElseClauseChildren<'db>))] -#[visit(drive(&crate::cst::EscapeInterpolation<'db>))] -#[visit(drive(&crate::cst::EscapeSequence<'db>))] -#[visit(drive(&crate::cst::ExceptClause<'db>))] -#[visit(drive(&crate::cst::ExceptClauseChildren<'db>))] -#[visit(drive(&crate::cst::ExceptGroupClause<'db>))] -#[visit(drive(&crate::cst::ExceptGroupClauseChildren<'db>))] -#[visit(drive(&crate::cst::ExecStatement<'db>))] -#[visit(drive(&crate::cst::ExecStatementChildren<'db>))] -#[visit(drive(&crate::cst::ExecStatementCode<'db>))] -#[visit(drive(&crate::cst::Expression<'db>))] -#[visit(drive(&crate::cst::ExpressionList<'db>))] -#[visit(drive(&crate::cst::ExpressionListChildren<'db>))] -#[visit(drive(&crate::cst::ExpressionStatement<'db>))] -#[visit(drive(&crate::cst::ExpressionStatementChildren<'db>))] -#[visit(drive(&crate::cst::False<'db>))] -#[visit(drive(&crate::cst::FinallyClause<'db>))] -#[visit(drive(&crate::cst::FinallyClauseChildren<'db>))] -#[visit(drive(&crate::cst::Float<'db>))] -#[visit(drive(&crate::cst::ForInClause<'db>))] -#[visit(drive(&crate::cst::ForInClauseChildren<'db>))] -#[visit(drive(&crate::cst::ForInClauseLeft<'db>))] -#[visit(drive(&crate::cst::ForInClauseRight<'db>))] -#[visit(drive(&crate::cst::ForStatement<'db>))] -#[visit(drive(&crate::cst::ForStatementChildren<'db>))] -#[visit(drive(&crate::cst::ForStatementLeft<'db>))] -#[visit(drive(&crate::cst::ForStatementRight<'db>))] -#[visit(drive(&crate::cst::FormatExpression<'db>))] -#[visit(drive(&crate::cst::FormatExpressionChildren<'db>))] -#[visit(drive(&crate::cst::FormatExpressionExpression<'db>))] -#[visit(drive(&crate::cst::FormatSpecifier<'db>))] -#[visit(drive(&crate::cst::FormatSpecifierChildren<'db>))] -#[visit(drive(&crate::cst::FunctionDefinitionChildren<'db>))] -#[visit(drive(&crate::cst::FutureImportStatement<'db>))] -#[visit(drive(&crate::cst::FutureImportStatementChildren<'db>))] -#[visit(drive(&crate::cst::FutureImportStatementName<'db>))] -#[visit(drive(&crate::cst::GeneratorExpression<'db>))] -#[visit(drive(&crate::cst::GeneratorExpressionChildren<'db>))] -#[visit(drive(&crate::cst::GenericType<'db>))] -#[visit(drive(&crate::cst::GenericTypeChildren<'db>))] -#[visit(drive(&crate::cst::GlobalStatement<'db>))] -#[visit(drive(&crate::cst::GlobalStatementChildren<'db>))] -#[visit(drive(&crate::cst::Identifier<'db>))] -#[visit(drive(&crate::cst::IfClause<'db>))] -#[visit(drive(&crate::cst::IfClauseChildren<'db>))] -#[visit(drive(&crate::cst::IfStatement<'db>))] -#[visit(drive(&crate::cst::IfStatementAlternative<'db>))] -#[visit(drive(&crate::cst::IfStatementChildren<'db>))] -#[visit(drive(&crate::cst::ImportFromStatement<'db>))] -#[visit(drive(&crate::cst::ImportFromStatementChildren<'db>))] -#[visit(drive(&crate::cst::ImportFromStatementModuleName<'db>))] -#[visit(drive(&crate::cst::ImportFromStatementName<'db>))] -#[visit(drive(&crate::cst::ImportPrefix<'db>))] -#[visit(drive(&crate::cst::ImportStatement<'db>))] -#[visit(drive(&crate::cst::ImportStatementChildren<'db>))] -#[visit(drive(&crate::cst::ImportStatementName<'db>))] -#[visit(drive(&crate::cst::Integer<'db>))] -#[visit(drive(&crate::cst::Interpolation<'db>))] -#[visit(drive(&crate::cst::InterpolationChildren<'db>))] -#[visit(drive(&crate::cst::InterpolationExpression<'db>))] -#[visit(drive(&crate::cst::KeywordArgument<'db>))] -#[visit(drive(&crate::cst::KeywordArgumentChildren<'db>))] -#[visit(drive(&crate::cst::KeywordPattern<'db>))] -#[visit(drive(&crate::cst::KeywordPatternChildren<'db>))] -#[visit(drive(&crate::cst::KeywordSeparator<'db>))] -#[visit(drive(&crate::cst::Lambda<'db>))] -#[visit(drive(&crate::cst::LambdaChildren<'db>))] -#[visit(drive(&crate::cst::LambdaParameters<'db>))] -#[visit(drive(&crate::cst::LambdaParametersChildren<'db>))] -#[visit(drive(&crate::cst::LineContinuation<'db>))] -#[visit(drive(&crate::cst::List<'db>))] -#[visit(drive(&crate::cst::ListChildren<'db>))] -#[visit(drive(&crate::cst::ListComprehension<'db>))] -#[visit(drive(&crate::cst::ListComprehensionChildren<'db>))] -#[visit(drive(&crate::cst::ListPattern<'db>))] -#[visit(drive(&crate::cst::ListPatternChildren<'db>))] -#[visit(drive(&crate::cst::ListSplat<'db>))] -#[visit(drive(&crate::cst::ListSplatChildren<'db>))] -#[visit(drive(&crate::cst::ListSplatPattern<'db>))] -#[visit(drive(&crate::cst::ListSplatPatternChildren<'db>))] -#[visit(drive(&crate::cst::MatchStatement<'db>))] -#[visit(drive(&crate::cst::MatchStatementChildren<'db>))] -#[visit(drive(&crate::cst::MemberType<'db>))] -#[visit(drive(&crate::cst::MemberTypeChildren<'db>))] -#[visit(drive(&crate::cst::ModuleChildren<'db>))] -#[visit(drive(&crate::cst::NamedExpression<'db>))] -#[visit(drive(&crate::cst::NamedExpressionChildren<'db>))] -#[visit(drive(&crate::cst::None<'db>))] -#[visit(drive(&crate::cst::NonlocalStatement<'db>))] -#[visit(drive(&crate::cst::NonlocalStatementChildren<'db>))] -#[visit(drive(&crate::cst::NotOperator<'db>))] -#[visit(drive(&crate::cst::NotOperatorChildren<'db>))] -#[visit(drive(&crate::cst::Pair<'db>))] -#[visit(drive(&crate::cst::PairChildren<'db>))] -#[visit(drive(&crate::cst::Parameter<'db>))] -#[visit(drive(&crate::cst::Parameters<'db>))] -#[visit(drive(&crate::cst::ParametersChildren<'db>))] -#[visit(drive(&crate::cst::ParenthesizedExpression<'db>))] -#[visit(drive(&crate::cst::ParenthesizedExpressionChildren<'db>))] -#[visit(drive(&crate::cst::ParenthesizedListSplat<'db>))] -#[visit(drive(&crate::cst::ParenthesizedListSplatChildren<'db>))] -#[visit(drive(&crate::cst::PassStatement<'db>))] -#[visit(drive(&crate::cst::Pattern<'db>))] -#[visit(drive(&crate::cst::PatternList<'db>))] -#[visit(drive(&crate::cst::PatternListChildren<'db>))] -#[visit(drive(&crate::cst::PositionalSeparator<'db>))] -#[visit(drive(&crate::cst::PrimaryExpression<'db>))] -#[visit(drive(&crate::cst::PrintStatement<'db>))] -#[visit(drive(&crate::cst::PrintStatementChildren<'db>))] -#[visit(drive(&crate::cst::RaiseStatement<'db>))] -#[visit(drive(&crate::cst::RaiseStatementChildren<'db>))] -#[visit(drive(&crate::cst::RelativeImport<'db>))] -#[visit(drive(&crate::cst::RelativeImportChildren<'db>))] -#[visit(drive(&crate::cst::ReturnStatement<'db>))] -#[visit(drive(&crate::cst::ReturnStatementChildren<'db>))] -#[visit(drive(&crate::cst::Set<'db>))] -#[visit(drive(&crate::cst::SetChildren<'db>))] -#[visit(drive(&crate::cst::SetComprehension<'db>))] -#[visit(drive(&crate::cst::SetComprehensionChildren<'db>))] -#[visit(drive(&crate::cst::SimpleStatement<'db>))] -#[visit(drive(&crate::cst::Slice<'db>))] -#[visit(drive(&crate::cst::SliceChildren<'db>))] -#[visit(drive(&crate::cst::SplatPattern<'db>))] -#[visit(drive(&crate::cst::SplatPatternChildren<'db>))] -#[visit(drive(&crate::cst::SplatType<'db>))] -#[visit(drive(&crate::cst::SplatTypeChildren<'db>))] -#[visit(drive(&crate::cst::String<'db>))] -#[visit(drive(&crate::cst::StringChildren<'db>))] -#[visit(drive(&crate::cst::StringContent<'db>))] -#[visit(drive(&crate::cst::StringContentChildren<'db>))] -#[visit(drive(&crate::cst::StringEnd<'db>))] -#[visit(drive(&crate::cst::StringStart<'db>))] -#[visit(drive(&crate::cst::Subscript<'db>))] -#[visit(drive(&crate::cst::SubscriptChildren<'db>))] -#[visit(drive(&crate::cst::SubscriptSubscript<'db>))] -#[visit(drive(&crate::cst::True<'db>))] -#[visit(drive(&crate::cst::TryStatement<'db>))] -#[visit(drive(&crate::cst::TryStatementChildren<'db>))] -#[visit(drive(&crate::cst::Tuple<'db>))] -#[visit(drive(&crate::cst::TupleChildren<'db>))] -#[visit(drive(&crate::cst::TuplePattern<'db>))] -#[visit(drive(&crate::cst::TuplePatternChildren<'db>))] -#[visit(drive(&crate::cst::Type<'db>))] -#[visit(drive(&crate::cst::TypeAliasStatement<'db>))] -#[visit(drive(&crate::cst::TypeAliasStatementChildren<'db>))] -#[visit(drive(&crate::cst::TypeChildren<'db>))] -#[visit(drive(&crate::cst::TypeConversion<'db>))] -#[visit(drive(&crate::cst::TypeParameter<'db>))] -#[visit(drive(&crate::cst::TypeParameterChildren<'db>))] -#[visit(drive(&crate::cst::TypedDefaultParameter<'db>))] -#[visit(drive(&crate::cst::TypedDefaultParameterChildren<'db>))] -#[visit(drive(&crate::cst::TypedParameter<'db>))] -#[visit(drive(&crate::cst::TypedParameterChildren<'db>))] -#[visit(drive(&crate::cst::UnaryOperator<'db>))] -#[visit(drive(&crate::cst::UnaryOperatorChildren<'db>))] -#[visit(drive(&crate::cst::UnaryOperatorOperator<'db>))] -#[visit(drive(&crate::cst::UnionPattern<'db>))] -#[visit(drive(&crate::cst::UnionPatternChildren<'db>))] -#[visit(drive(&crate::cst::UnionType<'db>))] -#[visit(drive(&crate::cst::UnionTypeChildren<'db>))] -#[visit(drive(&crate::cst::WhileStatement<'db>))] -#[visit(drive(&crate::cst::WhileStatementChildren<'db>))] -#[visit(drive(&crate::cst::WildcardImport<'db>))] -#[visit(drive(&crate::cst::WithClause<'db>))] -#[visit(drive(&crate::cst::WithClauseChildren<'db>))] -#[visit(drive(&crate::cst::WithItem<'db>))] -#[visit(drive(&crate::cst::WithItemChildren<'db>))] -#[visit(drive(&crate::cst::WithStatement<'db>))] -#[visit(drive(&crate::cst::WithStatementChildren<'db>))] -#[visit(drive(&crate::cst::Yield<'db>))] -#[visit(drive(&crate::cst::YieldChildren<'db>))] -#[visit(drive(&crate::cst::ClassDefinition<'db>))] -#[visit(drive(&crate::cst::FunctionDefinition<'db>))] -#[visit(drive(&crate::cst::Module<'db>))] -#[visit(drive(crate::cst::AliasedImport<'db>))] -#[visit(drive(crate::cst::AliasedImportChildren<'db>))] -#[visit(drive(crate::cst::AnonymousAmpersand<'db>))] -#[visit(drive(crate::cst::AnonymousAmpersandEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAnd<'db>))] -#[visit(drive(crate::cst::AnonymousAs<'db>))] -#[visit(drive(crate::cst::AnonymousAssert<'db>))] -#[visit(drive(crate::cst::AnonymousAsterisk<'db>))] -#[visit(drive(crate::cst::AnonymousAsteriskAsterisk<'db>))] -#[visit(drive(crate::cst::AnonymousAsteriskAsteriskEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAsteriskEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAsync<'db>))] -#[visit(drive(crate::cst::AnonymousAt<'db>))] -#[visit(drive(crate::cst::AnonymousAtEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAwait<'db>))] -#[visit(drive(crate::cst::AnonymousBackslash<'db>))] -#[visit(drive(crate::cst::AnonymousBangEquals<'db>))] -#[visit(drive(crate::cst::AnonymousBreak<'db>))] -#[visit(drive(crate::cst::AnonymousCaret<'db>))] -#[visit(drive(crate::cst::AnonymousCaretEquals<'db>))] -#[visit(drive(crate::cst::AnonymousCase<'db>))] -#[visit(drive(crate::cst::AnonymousClass<'db>))] -#[visit(drive(crate::cst::AnonymousCloseBrace<'db>))] -#[visit(drive(crate::cst::AnonymousCloseBracket<'db>))] -#[visit(drive(crate::cst::AnonymousCloseParen<'db>))] -#[visit(drive(crate::cst::AnonymousColon<'db>))] -#[visit(drive(crate::cst::AnonymousColonEquals<'db>))] -#[visit(drive(crate::cst::AnonymousComma<'db>))] -#[visit(drive(crate::cst::AnonymousContinue<'db>))] -#[visit(drive(crate::cst::AnonymousDef<'db>))] -#[visit(drive(crate::cst::AnonymousDel<'db>))] -#[visit(drive(crate::cst::AnonymousDot<'db>))] -#[visit(drive(crate::cst::AnonymousElif<'db>))] -#[visit(drive(crate::cst::AnonymousElse<'db>))] -#[visit(drive(crate::cst::AnonymousEquals<'db>))] -#[visit(drive(crate::cst::AnonymousEqualsEquals<'db>))] -#[visit(drive(crate::cst::AnonymousExcept<'db>))] -#[visit(drive(crate::cst::AnonymousExceptAsterisk<'db>))] -#[visit(drive(crate::cst::AnonymousExec<'db>))] -#[visit(drive(crate::cst::AnonymousFinally<'db>))] -#[visit(drive(crate::cst::AnonymousFor<'db>))] -#[visit(drive(crate::cst::AnonymousFrom<'db>))] -#[visit(drive(crate::cst::AnonymousFuture<'db>))] -#[visit(drive(crate::cst::AnonymousGlobal<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanGreaterThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousIf<'db>))] -#[visit(drive(crate::cst::AnonymousImport<'db>))] -#[visit(drive(crate::cst::AnonymousIn<'db>))] -#[visit(drive(crate::cst::AnonymousIs<'db>))] -#[visit(drive(crate::cst::AnonymousIsNot<'db>))] -#[visit(drive(crate::cst::AnonymousLambda<'db>))] -#[visit(drive(crate::cst::AnonymousLessThan<'db>))] -#[visit(drive(crate::cst::AnonymousLessThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousLessThanGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousLessThanLessThan<'db>))] -#[visit(drive(crate::cst::AnonymousLessThanLessThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousMatch<'db>))] -#[visit(drive(crate::cst::AnonymousMinus<'db>))] -#[visit(drive(crate::cst::AnonymousMinusEquals<'db>))] -#[visit(drive(crate::cst::AnonymousMinusGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousNonlocal<'db>))] -#[visit(drive(crate::cst::AnonymousNot<'db>))] -#[visit(drive(crate::cst::AnonymousNotIn<'db>))] -#[visit(drive(crate::cst::AnonymousOpenBrace<'db>))] -#[visit(drive(crate::cst::AnonymousOpenBracket<'db>))] -#[visit(drive(crate::cst::AnonymousOpenParen<'db>))] -#[visit(drive(crate::cst::AnonymousOr<'db>))] -#[visit(drive(crate::cst::AnonymousPass<'db>))] -#[visit(drive(crate::cst::AnonymousPercent<'db>))] -#[visit(drive(crate::cst::AnonymousPercentEquals<'db>))] -#[visit(drive(crate::cst::AnonymousPipe<'db>))] -#[visit(drive(crate::cst::AnonymousPipeEquals<'db>))] -#[visit(drive(crate::cst::AnonymousPlus<'db>))] -#[visit(drive(crate::cst::AnonymousPlusEquals<'db>))] -#[visit(drive(crate::cst::AnonymousPrint<'db>))] -#[visit(drive(crate::cst::AnonymousRaise<'db>))] -#[visit(drive(crate::cst::AnonymousReturn<'db>))] -#[visit(drive(crate::cst::AnonymousSemicolon<'db>))] -#[visit(drive(crate::cst::AnonymousSlash<'db>))] -#[visit(drive(crate::cst::AnonymousSlashEquals<'db>))] -#[visit(drive(crate::cst::AnonymousSlashSlash<'db>))] -#[visit(drive(crate::cst::AnonymousSlashSlashEquals<'db>))] -#[visit(drive(crate::cst::AnonymousTilde<'db>))] -#[visit(drive(crate::cst::AnonymousTry<'db>))] -#[visit(drive(crate::cst::AnonymousType<'db>))] -#[visit(drive(crate::cst::AnonymousUnderscore<'db>))] -#[visit(drive(crate::cst::AnonymousWhile<'db>))] -#[visit(drive(crate::cst::AnonymousWith<'db>))] -#[visit(drive(crate::cst::AnonymousYield<'db>))] -#[visit(drive(crate::cst::ArgumentList<'db>))] -#[visit(drive(crate::cst::ArgumentListChildren<'db>))] -#[visit(drive(crate::cst::AsPattern<'db>))] -#[visit(drive(crate::cst::AsPatternChildren<'db>))] -#[visit(drive(crate::cst::AsPatternTarget<'db>))] -#[visit(drive(crate::cst::AssertStatement<'db>))] -#[visit(drive(crate::cst::AssertStatementChildren<'db>))] -#[visit(drive(crate::cst::Assignment<'db>))] -#[visit(drive(crate::cst::AssignmentChildren<'db>))] -#[visit(drive(crate::cst::AssignmentLeft<'db>))] -#[visit(drive(crate::cst::AssignmentRight<'db>))] -#[visit(drive(crate::cst::Attribute<'db>))] -#[visit(drive(crate::cst::AttributeChildren<'db>))] -#[visit(drive(crate::cst::AugmentedAssignment<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentChildren<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentLeft<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentOperator<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentRight<'db>))] -#[visit(drive(crate::cst::Await<'db>))] -#[visit(drive(crate::cst::AwaitChildren<'db>))] -#[visit(drive(crate::cst::BinaryOperator<'db>))] -#[visit(drive(crate::cst::BinaryOperatorChildren<'db>))] -#[visit(drive(crate::cst::BinaryOperatorOperator<'db>))] -#[visit(drive(crate::cst::Block<'db>))] -#[visit(drive(crate::cst::BlockChildren<'db>))] -#[visit(drive(crate::cst::BooleanOperator<'db>))] -#[visit(drive(crate::cst::BooleanOperatorChildren<'db>))] -#[visit(drive(crate::cst::BooleanOperatorOperator<'db>))] -#[visit(drive(crate::cst::BreakStatement<'db>))] -#[visit(drive(crate::cst::Call<'db>))] -#[visit(drive(crate::cst::CallArguments<'db>))] -#[visit(drive(crate::cst::CallChildren<'db>))] -#[visit(drive(crate::cst::CaseClause<'db>))] -#[visit(drive(crate::cst::CaseClauseChildren<'db>))] -#[visit(drive(crate::cst::CasePattern<'db>))] -#[visit(drive(crate::cst::CasePatternChildren<'db>))] -#[visit(drive(crate::cst::Chevron<'db>))] -#[visit(drive(crate::cst::ChevronChildren<'db>))] -#[visit(drive(crate::cst::ClassDefinitionChildren<'db>))] -#[visit(drive(crate::cst::ClassPattern<'db>))] -#[visit(drive(crate::cst::ClassPatternChildren<'db>))] -#[visit(drive(crate::cst::Comment<'db>))] -#[visit(drive(crate::cst::ComparisonOperator<'db>))] -#[visit(drive(crate::cst::ComparisonOperatorChildren<'db>))] -#[visit(drive(crate::cst::ComparisonOperatorOperators<'db>))] -#[visit(drive(crate::cst::ComplexPattern<'db>))] -#[visit(drive(crate::cst::ComplexPatternChildren<'db>))] -#[visit(drive(crate::cst::CompoundStatement<'db>))] -#[visit(drive(crate::cst::ConcatenatedString<'db>))] -#[visit(drive(crate::cst::ConcatenatedStringChildren<'db>))] -#[visit(drive(crate::cst::ConditionalExpression<'db>))] -#[visit(drive(crate::cst::ConditionalExpressionChildren<'db>))] -#[visit(drive(crate::cst::ConstrainedType<'db>))] -#[visit(drive(crate::cst::ConstrainedTypeChildren<'db>))] -#[visit(drive(crate::cst::ContinueStatement<'db>))] -#[visit(drive(crate::cst::DecoratedDefinition<'db>))] -#[visit(drive(crate::cst::DecoratedDefinitionChildren<'db>))] -#[visit(drive(crate::cst::DecoratedDefinitionDefinition<'db>))] -#[visit(drive(crate::cst::Decorator<'db>))] -#[visit(drive(crate::cst::DecoratorChildren<'db>))] -#[visit(drive(crate::cst::DefaultParameter<'db>))] -#[visit(drive(crate::cst::DefaultParameterChildren<'db>))] -#[visit(drive(crate::cst::DefaultParameterName<'db>))] -#[visit(drive(crate::cst::DeleteStatement<'db>))] -#[visit(drive(crate::cst::DeleteStatementChildren<'db>))] -#[visit(drive(crate::cst::DictPattern<'db>))] -#[visit(drive(crate::cst::DictPatternChildren<'db>))] -#[visit(drive(crate::cst::DictPatternKey<'db>))] -#[visit(drive(crate::cst::Dictionary<'db>))] -#[visit(drive(crate::cst::DictionaryChildren<'db>))] -#[visit(drive(crate::cst::DictionaryComprehension<'db>))] -#[visit(drive(crate::cst::DictionaryComprehensionChildren<'db>))] -#[visit(drive(crate::cst::DictionarySplat<'db>))] -#[visit(drive(crate::cst::DictionarySplatChildren<'db>))] -#[visit(drive(crate::cst::DictionarySplatPattern<'db>))] -#[visit(drive(crate::cst::DictionarySplatPatternChildren<'db>))] -#[visit(drive(crate::cst::DottedName<'db>))] -#[visit(drive(crate::cst::DottedNameChildren<'db>))] -#[visit(drive(crate::cst::ElifClause<'db>))] -#[visit(drive(crate::cst::ElifClauseChildren<'db>))] -#[visit(drive(crate::cst::Ellipsis<'db>))] -#[visit(drive(crate::cst::ElseClause<'db>))] -#[visit(drive(crate::cst::ElseClauseChildren<'db>))] -#[visit(drive(crate::cst::EscapeInterpolation<'db>))] -#[visit(drive(crate::cst::EscapeSequence<'db>))] -#[visit(drive(crate::cst::ExceptClause<'db>))] -#[visit(drive(crate::cst::ExceptClauseChildren<'db>))] -#[visit(drive(crate::cst::ExceptGroupClause<'db>))] -#[visit(drive(crate::cst::ExceptGroupClauseChildren<'db>))] -#[visit(drive(crate::cst::ExecStatement<'db>))] -#[visit(drive(crate::cst::ExecStatementChildren<'db>))] -#[visit(drive(crate::cst::ExecStatementCode<'db>))] -#[visit(drive(crate::cst::Expression<'db>))] -#[visit(drive(crate::cst::ExpressionList<'db>))] -#[visit(drive(crate::cst::ExpressionListChildren<'db>))] -#[visit(drive(crate::cst::ExpressionStatement<'db>))] -#[visit(drive(crate::cst::ExpressionStatementChildren<'db>))] -#[visit(drive(crate::cst::False<'db>))] -#[visit(drive(crate::cst::FinallyClause<'db>))] -#[visit(drive(crate::cst::FinallyClauseChildren<'db>))] -#[visit(drive(crate::cst::Float<'db>))] -#[visit(drive(crate::cst::ForInClause<'db>))] -#[visit(drive(crate::cst::ForInClauseChildren<'db>))] -#[visit(drive(crate::cst::ForInClauseLeft<'db>))] -#[visit(drive(crate::cst::ForInClauseRight<'db>))] -#[visit(drive(crate::cst::ForStatement<'db>))] -#[visit(drive(crate::cst::ForStatementChildren<'db>))] -#[visit(drive(crate::cst::ForStatementLeft<'db>))] -#[visit(drive(crate::cst::ForStatementRight<'db>))] -#[visit(drive(crate::cst::FormatExpression<'db>))] -#[visit(drive(crate::cst::FormatExpressionChildren<'db>))] -#[visit(drive(crate::cst::FormatExpressionExpression<'db>))] -#[visit(drive(crate::cst::FormatSpecifier<'db>))] -#[visit(drive(crate::cst::FormatSpecifierChildren<'db>))] -#[visit(drive(crate::cst::FunctionDefinitionChildren<'db>))] -#[visit(drive(crate::cst::FutureImportStatement<'db>))] -#[visit(drive(crate::cst::FutureImportStatementChildren<'db>))] -#[visit(drive(crate::cst::FutureImportStatementName<'db>))] -#[visit(drive(crate::cst::GeneratorExpression<'db>))] -#[visit(drive(crate::cst::GeneratorExpressionChildren<'db>))] -#[visit(drive(crate::cst::GenericType<'db>))] -#[visit(drive(crate::cst::GenericTypeChildren<'db>))] -#[visit(drive(crate::cst::GlobalStatement<'db>))] -#[visit(drive(crate::cst::GlobalStatementChildren<'db>))] -#[visit(drive(crate::cst::Identifier<'db>))] -#[visit(drive(crate::cst::IfClause<'db>))] -#[visit(drive(crate::cst::IfClauseChildren<'db>))] -#[visit(drive(crate::cst::IfStatement<'db>))] -#[visit(drive(crate::cst::IfStatementAlternative<'db>))] -#[visit(drive(crate::cst::IfStatementChildren<'db>))] -#[visit(drive(crate::cst::ImportFromStatement<'db>))] -#[visit(drive(crate::cst::ImportFromStatementChildren<'db>))] -#[visit(drive(crate::cst::ImportFromStatementModuleName<'db>))] -#[visit(drive(crate::cst::ImportFromStatementName<'db>))] -#[visit(drive(crate::cst::ImportPrefix<'db>))] -#[visit(drive(crate::cst::ImportStatement<'db>))] -#[visit(drive(crate::cst::ImportStatementChildren<'db>))] -#[visit(drive(crate::cst::ImportStatementName<'db>))] -#[visit(drive(crate::cst::Integer<'db>))] -#[visit(drive(crate::cst::Interpolation<'db>))] -#[visit(drive(crate::cst::InterpolationChildren<'db>))] -#[visit(drive(crate::cst::InterpolationExpression<'db>))] -#[visit(drive(crate::cst::KeywordArgument<'db>))] -#[visit(drive(crate::cst::KeywordArgumentChildren<'db>))] -#[visit(drive(crate::cst::KeywordPattern<'db>))] -#[visit(drive(crate::cst::KeywordPatternChildren<'db>))] -#[visit(drive(crate::cst::KeywordSeparator<'db>))] -#[visit(drive(crate::cst::Lambda<'db>))] -#[visit(drive(crate::cst::LambdaChildren<'db>))] -#[visit(drive(crate::cst::LambdaParameters<'db>))] -#[visit(drive(crate::cst::LambdaParametersChildren<'db>))] -#[visit(drive(crate::cst::LineContinuation<'db>))] -#[visit(drive(crate::cst::List<'db>))] -#[visit(drive(crate::cst::ListChildren<'db>))] -#[visit(drive(crate::cst::ListComprehension<'db>))] -#[visit(drive(crate::cst::ListComprehensionChildren<'db>))] -#[visit(drive(crate::cst::ListPattern<'db>))] -#[visit(drive(crate::cst::ListPatternChildren<'db>))] -#[visit(drive(crate::cst::ListSplat<'db>))] -#[visit(drive(crate::cst::ListSplatChildren<'db>))] -#[visit(drive(crate::cst::ListSplatPattern<'db>))] -#[visit(drive(crate::cst::ListSplatPatternChildren<'db>))] -#[visit(drive(crate::cst::MatchStatement<'db>))] -#[visit(drive(crate::cst::MatchStatementChildren<'db>))] -#[visit(drive(crate::cst::MemberType<'db>))] -#[visit(drive(crate::cst::MemberTypeChildren<'db>))] -#[visit(drive(crate::cst::ModuleChildren<'db>))] -#[visit(drive(crate::cst::NamedExpression<'db>))] -#[visit(drive(crate::cst::NamedExpressionChildren<'db>))] -#[visit(drive(crate::cst::None<'db>))] -#[visit(drive(crate::cst::NonlocalStatement<'db>))] -#[visit(drive(crate::cst::NonlocalStatementChildren<'db>))] -#[visit(drive(crate::cst::NotOperator<'db>))] -#[visit(drive(crate::cst::NotOperatorChildren<'db>))] -#[visit(drive(crate::cst::Pair<'db>))] -#[visit(drive(crate::cst::PairChildren<'db>))] -#[visit(drive(crate::cst::Parameter<'db>))] -#[visit(drive(crate::cst::Parameters<'db>))] -#[visit(drive(crate::cst::ParametersChildren<'db>))] -#[visit(drive(crate::cst::ParenthesizedExpression<'db>))] -#[visit(drive(crate::cst::ParenthesizedExpressionChildren<'db>))] -#[visit(drive(crate::cst::ParenthesizedListSplat<'db>))] -#[visit(drive(crate::cst::ParenthesizedListSplatChildren<'db>))] -#[visit(drive(crate::cst::PassStatement<'db>))] -#[visit(drive(crate::cst::Pattern<'db>))] -#[visit(drive(crate::cst::PatternList<'db>))] -#[visit(drive(crate::cst::PatternListChildren<'db>))] -#[visit(drive(crate::cst::PositionalSeparator<'db>))] -#[visit(drive(crate::cst::PrimaryExpression<'db>))] -#[visit(drive(crate::cst::PrintStatement<'db>))] -#[visit(drive(crate::cst::PrintStatementChildren<'db>))] -#[visit(drive(crate::cst::RaiseStatement<'db>))] -#[visit(drive(crate::cst::RaiseStatementChildren<'db>))] -#[visit(drive(crate::cst::RelativeImport<'db>))] -#[visit(drive(crate::cst::RelativeImportChildren<'db>))] -#[visit(drive(crate::cst::ReturnStatement<'db>))] -#[visit(drive(crate::cst::ReturnStatementChildren<'db>))] -#[visit(drive(crate::cst::Set<'db>))] -#[visit(drive(crate::cst::SetChildren<'db>))] -#[visit(drive(crate::cst::SetComprehension<'db>))] -#[visit(drive(crate::cst::SetComprehensionChildren<'db>))] -#[visit(drive(crate::cst::SimpleStatement<'db>))] -#[visit(drive(crate::cst::Slice<'db>))] -#[visit(drive(crate::cst::SliceChildren<'db>))] -#[visit(drive(crate::cst::SplatPattern<'db>))] -#[visit(drive(crate::cst::SplatPatternChildren<'db>))] -#[visit(drive(crate::cst::SplatType<'db>))] -#[visit(drive(crate::cst::SplatTypeChildren<'db>))] -#[visit(drive(crate::cst::String<'db>))] -#[visit(drive(crate::cst::StringChildren<'db>))] -#[visit(drive(crate::cst::StringContent<'db>))] -#[visit(drive(crate::cst::StringContentChildren<'db>))] -#[visit(drive(crate::cst::StringEnd<'db>))] -#[visit(drive(crate::cst::StringStart<'db>))] -#[visit(drive(crate::cst::Subscript<'db>))] -#[visit(drive(crate::cst::SubscriptChildren<'db>))] -#[visit(drive(crate::cst::SubscriptSubscript<'db>))] -#[visit(drive(crate::cst::True<'db>))] -#[visit(drive(crate::cst::TryStatement<'db>))] -#[visit(drive(crate::cst::TryStatementChildren<'db>))] -#[visit(drive(crate::cst::Tuple<'db>))] -#[visit(drive(crate::cst::TupleChildren<'db>))] -#[visit(drive(crate::cst::TuplePattern<'db>))] -#[visit(drive(crate::cst::TuplePatternChildren<'db>))] -#[visit(drive(crate::cst::Type<'db>))] -#[visit(drive(crate::cst::TypeAliasStatement<'db>))] -#[visit(drive(crate::cst::TypeAliasStatementChildren<'db>))] -#[visit(drive(crate::cst::TypeChildren<'db>))] -#[visit(drive(crate::cst::TypeConversion<'db>))] -#[visit(drive(crate::cst::TypeParameter<'db>))] -#[visit(drive(crate::cst::TypeParameterChildren<'db>))] -#[visit(drive(crate::cst::TypedDefaultParameter<'db>))] -#[visit(drive(crate::cst::TypedDefaultParameterChildren<'db>))] -#[visit(drive(crate::cst::TypedParameter<'db>))] -#[visit(drive(crate::cst::TypedParameterChildren<'db>))] -#[visit(drive(crate::cst::UnaryOperator<'db>))] -#[visit(drive(crate::cst::UnaryOperatorChildren<'db>))] -#[visit(drive(crate::cst::UnaryOperatorOperator<'db>))] -#[visit(drive(crate::cst::UnionPattern<'db>))] -#[visit(drive(crate::cst::UnionPatternChildren<'db>))] -#[visit(drive(crate::cst::UnionType<'db>))] -#[visit(drive(crate::cst::UnionTypeChildren<'db>))] -#[visit(drive(crate::cst::WhileStatement<'db>))] -#[visit(drive(crate::cst::WhileStatementChildren<'db>))] -#[visit(drive(crate::cst::WildcardImport<'db>))] -#[visit(drive(crate::cst::WithClause<'db>))] -#[visit(drive(crate::cst::WithClauseChildren<'db>))] -#[visit(drive(crate::cst::WithItem<'db>))] -#[visit(drive(crate::cst::WithItemChildren<'db>))] -#[visit(drive(crate::cst::WithStatement<'db>))] -#[visit(drive(crate::cst::WithStatementChildren<'db>))] -#[visit(drive(crate::cst::Yield<'db>))] -#[visit(drive(crate::cst::YieldChildren<'db>))] -#[visit(drive(forBox))] -#[visit(drive(forVec))] -#[visit(drive(forOption))] -#[visit( - enter(ClassDefinition:crate::cst::ClassDefinition<'db>), - enter(FunctionDefinition:crate::cst::FunctionDefinition<'db>), - enter(Module:crate::cst::Module<'db>) -)] +#[salsa::tracked] pub struct Definitions<'db> { - pub classes: BTreeMap>>, - pub constants: BTreeMap>>, - pub functions: BTreeMap>>, - phantom: std::marker::PhantomData<&'db ()>, + #[return_ref] + pub _classes: BTreeMap>, + #[return_ref] + pub _constants: BTreeMap>, + #[return_ref] + pub _functions: BTreeMap>, } impl<'db> Definitions<'db> { - fn enter_ClassDefinition(&mut self, node: &crate::cst::ClassDefinition<'db>) { - ///Code for query: (class_definition name: (identifier) @name) @definition.class - let name = &*node.name; - self.classes.entry(name.source()).or_insert(Vec::new()).push(node.clone()); - } - fn enter_FunctionDefinition(&mut self, node: &crate::cst::FunctionDefinition<'db>) { - ///Code for query: (function_definition name: (identifier) @name) @definition.function - let name = &*node.name; - self.functions.entry(name.source()).or_insert(Vec::new()).push(node.clone()); - } - fn enter_Module(&mut self, node: &crate::cst::Module<'db>) { - ///Code for query: (module (expression_statement (assignment left: (identifier) @name) @definition.constant)) - for child in node.children().into_iter() { - if let crate::cst::ModuleChildren::ExpressionStatement(child) = child { - ///Code for query: (module (expression_statement (assignment left: (identifier) @name) @definition.constant)) - for child in child.children().into_iter() { - if let crate::cst::ExpressionStatementChildren::Assignment(child) = child { - ///Code for query: (module (expression_statement (assignment left: (identifier) @name) @definition.constant)) - let left = &*child.left; - self.constants - .entry(left.source()) - .or_insert(Vec::new()) - .push(node.clone()); + pub fn visit( + db: &'db dyn salsa::Database, + root: &'db crate::cst::Parsed<'db>, + ) -> Self { + let mut classes: BTreeMap> = BTreeMap::new(); + let mut constants: BTreeMap> = BTreeMap::new(); + let mut functions: BTreeMap> = BTreeMap::new(); + let tree = root.tree(db); + for (node, id) in tree.descendants(&root.program(db)) { + match node { + crate::cst::NodeTypes::ClassDefinition(node) => { + ///Code for query: (class_definition name: (identifier) @name) @definition.class + let name = node.name(tree); + classes.entry(name.source()).or_default().push(id); + } + crate::cst::NodeTypes::FunctionDefinition(node) => { + ///Code for query: (function_definition name: (identifier) @name) @definition.function + let name = node.name(tree); + functions.entry(name.source()).or_default().push(id); + } + crate::cst::NodeTypes::Module(node) => { + ///Code for query: (module (expression_statement (assignment left: (identifier) @name) @definition.constant)) + for child in node.children(tree) { + if let crate::cst::ModuleChildrenRef::ExpressionStatement( + child, + ) = child { + ///Code for query: (module (expression_statement (assignment left: (identifier) @name) @definition.constant)) + for child in child.children(tree) { + if let crate::cst::ExpressionStatementChildrenRef::Assignment( + child, + ) = child { + ///Code for query: (module (expression_statement (assignment left: (identifier) @name) @definition.constant)) + let left = child.left(tree); + constants.entry(left.source()).or_default().push(id); + } + break; + } + } + break; } - break; } + _ => {} } - break; } + Self::new(db, classes, constants, functions) + } + pub fn default(db: &'db dyn salsa::Database) -> Self { + let mut classes: BTreeMap> = BTreeMap::new(); + let mut constants: BTreeMap> = BTreeMap::new(); + let mut functions: BTreeMap> = BTreeMap::new(); + Self::new(db, classes, constants, functions) + } + pub fn classes( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._classes(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() + } + pub fn constants( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._constants(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() + } + pub fn functions( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._functions(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() } } diff --git a/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__typescript.snap b/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__typescript.snap index ed0a1009..b3bee56b 100644 --- a/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__typescript.snap +++ b/codegen-sdk-ast-generator/src/snapshots/codegen_sdk_ast_generator__visitor__tests__typescript.snap @@ -2,1117 +2,148 @@ source: codegen-sdk-ast-generator/src/visitor.rs expression: "codegen_sdk_common::generator::format_code_string(&visitor.to_string()).unwrap()" --- -#[derive(Visitor, Visit, Debug, Clone, Eq, PartialEq, salsa::Update, Hash, Default)] -#[visit(drive(&crate::cst::AbstractClassDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::AbstractMethodSignatureChildren<'db>))] -#[visit(drive(&crate::cst::AbstractMethodSignatureName<'db>))] -#[visit(drive(&crate::cst::AbstractMethodSignatureReturnType<'db>))] -#[visit(drive(&crate::cst::AccessibilityModifier<'db>))] -#[visit(drive(&crate::cst::AddingTypeAnnotation<'db>))] -#[visit(drive(&crate::cst::AddingTypeAnnotationChildren<'db>))] -#[visit(drive(&crate::cst::AmbientDeclaration<'db>))] -#[visit(drive(&crate::cst::AmbientDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::AnonymousAbstract<'db>))] -#[visit(drive(&crate::cst::AnonymousAccessor<'db>))] -#[visit(drive(&crate::cst::AnonymousAmpersand<'db>))] -#[visit(drive(&crate::cst::AnonymousAmpersandAmpersand<'db>))] -#[visit(drive(&crate::cst::AnonymousAmpersandAmpersandEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAmpersandEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAny<'db>))] -#[visit(drive(&crate::cst::AnonymousAs<'db>))] -#[visit(drive(&crate::cst::AnonymousAssert<'db>))] -#[visit(drive(&crate::cst::AnonymousAsserts<'db>))] -#[visit(drive(&crate::cst::AnonymousAsterisk<'db>))] -#[visit(drive(&crate::cst::AnonymousAsteriskAsterisk<'db>))] -#[visit(drive(&crate::cst::AnonymousAsteriskAsteriskEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAsteriskEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousAsync<'db>))] -#[visit(drive(&crate::cst::AnonymousAt<'db>))] -#[visit(drive(&crate::cst::AnonymousAwait<'db>))] -#[visit(drive(&crate::cst::AnonymousBacktick<'db>))] -#[visit(drive(&crate::cst::AnonymousBang<'db>))] -#[visit(drive(&crate::cst::AnonymousBangEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousBangEqualsEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousBoolean<'db>))] -#[visit(drive(&crate::cst::AnonymousBreak<'db>))] -#[visit(drive(&crate::cst::AnonymousCaret<'db>))] -#[visit(drive(&crate::cst::AnonymousCaretEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousCase<'db>))] -#[visit(drive(&crate::cst::AnonymousCatch<'db>))] -#[visit(drive(&crate::cst::AnonymousClass<'db>))] -#[visit(drive(&crate::cst::AnonymousCloseBrace<'db>))] -#[visit(drive(&crate::cst::AnonymousCloseBracket<'db>))] -#[visit(drive(&crate::cst::AnonymousCloseParen<'db>))] -#[visit(drive(&crate::cst::AnonymousColon<'db>))] -#[visit(drive(&crate::cst::AnonymousComma<'db>))] -#[visit(drive(&crate::cst::AnonymousConst<'db>))] -#[visit(drive(&crate::cst::AnonymousContinue<'db>))] -#[visit(drive(&crate::cst::AnonymousDebugger<'db>))] -#[visit(drive(&crate::cst::AnonymousDeclare<'db>))] -#[visit(drive(&crate::cst::AnonymousDefault<'db>))] -#[visit(drive(&crate::cst::AnonymousDelete<'db>))] -#[visit(drive(&crate::cst::AnonymousDo<'db>))] -#[visit(drive(&crate::cst::AnonymousDollarOpenBrace<'db>))] -#[visit(drive(&crate::cst::AnonymousDot<'db>))] -#[visit(drive(&crate::cst::AnonymousDotDotDot<'db>))] -#[visit(drive(&crate::cst::AnonymousDoubleQuote<'db>))] -#[visit(drive(&crate::cst::AnonymousElse<'db>))] -#[visit(drive(&crate::cst::AnonymousEnum<'db>))] -#[visit(drive(&crate::cst::AnonymousEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousEqualsEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousEqualsEqualsEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousEqualsGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousExport<'db>))] -#[visit(drive(&crate::cst::AnonymousExtends<'db>))] -#[visit(drive(&crate::cst::AnonymousFinally<'db>))] -#[visit(drive(&crate::cst::AnonymousFor<'db>))] -#[visit(drive(&crate::cst::AnonymousFrom<'db>))] -#[visit(drive(&crate::cst::AnonymousFunction<'db>))] -#[visit(drive(&crate::cst::AnonymousGet<'db>))] -#[visit(drive(&crate::cst::AnonymousGlobal<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanGreaterThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanGreaterThanGreaterThan<'db>))] -#[visit(drive(&crate::cst::AnonymousGreaterThanGreaterThanGreaterThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousIf<'db>))] -#[visit(drive(&crate::cst::AnonymousImplements<'db>))] -#[visit(drive(&crate::cst::AnonymousImport<'db>))] -#[visit(drive(&crate::cst::AnonymousIn<'db>))] -#[visit(drive(&crate::cst::AnonymousInfer<'db>))] -#[visit(drive(&crate::cst::AnonymousInstanceof<'db>))] -#[visit(drive(&crate::cst::AnonymousInterface<'db>))] -#[visit(drive(&crate::cst::AnonymousIs<'db>))] -#[visit(drive(&crate::cst::AnonymousKeyof<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThan<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThanLessThan<'db>))] -#[visit(drive(&crate::cst::AnonymousLessThanLessThanEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousLet<'db>))] -#[visit(drive(&crate::cst::AnonymousMeta<'db>))] -#[visit(drive(&crate::cst::AnonymousMinus<'db>))] -#[visit(drive(&crate::cst::AnonymousMinusEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousMinusMinus<'db>))] -#[visit(drive(&crate::cst::AnonymousMinusQuestionMarkColon<'db>))] -#[visit(drive(&crate::cst::AnonymousModule<'db>))] -#[visit(drive(&crate::cst::AnonymousNamespace<'db>))] -#[visit(drive(&crate::cst::AnonymousNever<'db>))] -#[visit(drive(&crate::cst::AnonymousNew<'db>))] -#[visit(drive(&crate::cst::AnonymousNumber<'db>))] -#[visit(drive(&crate::cst::AnonymousObject<'db>))] -#[visit(drive(&crate::cst::AnonymousOf<'db>))] -#[visit(drive(&crate::cst::AnonymousOpenBrace<'db>))] -#[visit(drive(&crate::cst::AnonymousOpenBracePipe<'db>))] -#[visit(drive(&crate::cst::AnonymousOpenBracket<'db>))] -#[visit(drive(&crate::cst::AnonymousOpenParen<'db>))] -#[visit(drive(&crate::cst::AnonymousOverride<'db>))] -#[visit(drive(&crate::cst::AnonymousPercent<'db>))] -#[visit(drive(&crate::cst::AnonymousPercentEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousPipe<'db>))] -#[visit(drive(&crate::cst::AnonymousPipeCloseBrace<'db>))] -#[visit(drive(&crate::cst::AnonymousPipeEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousPipePipe<'db>))] -#[visit(drive(&crate::cst::AnonymousPipePipeEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousPlus<'db>))] -#[visit(drive(&crate::cst::AnonymousPlusEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousPlusPlus<'db>))] -#[visit(drive(&crate::cst::AnonymousPlusQuestionMarkColon<'db>))] -#[visit(drive(&crate::cst::AnonymousPrivate<'db>))] -#[visit(drive(&crate::cst::AnonymousProtected<'db>))] -#[visit(drive(&crate::cst::AnonymousPublic<'db>))] -#[visit(drive(&crate::cst::AnonymousQuestionMark<'db>))] -#[visit(drive(&crate::cst::AnonymousQuestionMarkColon<'db>))] -#[visit(drive(&crate::cst::AnonymousQuestionMarkDot<'db>))] -#[visit(drive(&crate::cst::AnonymousQuestionMarkQuestionMark<'db>))] -#[visit(drive(&crate::cst::AnonymousQuestionMarkQuestionMarkEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousReadonly<'db>))] -#[visit(drive(&crate::cst::AnonymousRequire<'db>))] -#[visit(drive(&crate::cst::AnonymousReturn<'db>))] -#[visit(drive(&crate::cst::AnonymousSatisfies<'db>))] -#[visit(drive(&crate::cst::AnonymousSemicolon<'db>))] -#[visit(drive(&crate::cst::AnonymousSet<'db>))] -#[visit(drive(&crate::cst::AnonymousSingleQuote<'db>))] -#[visit(drive(&crate::cst::AnonymousSlash<'db>))] -#[visit(drive(&crate::cst::AnonymousSlashEquals<'db>))] -#[visit(drive(&crate::cst::AnonymousStatic<'db>))] -#[visit(drive(&crate::cst::AnonymousString<'db>))] -#[visit(drive(&crate::cst::AnonymousSwitch<'db>))] -#[visit(drive(&crate::cst::AnonymousSymbol<'db>))] -#[visit(drive(&crate::cst::AnonymousTarget<'db>))] -#[visit(drive(&crate::cst::AnonymousThrow<'db>))] -#[visit(drive(&crate::cst::AnonymousTilde<'db>))] -#[visit(drive(&crate::cst::AnonymousTry<'db>))] -#[visit(drive(&crate::cst::AnonymousType<'db>))] -#[visit(drive(&crate::cst::AnonymousTypeof<'db>))] -#[visit(drive(&crate::cst::AnonymousUniqueSymbol<'db>))] -#[visit(drive(&crate::cst::AnonymousUnknown<'db>))] -#[visit(drive(&crate::cst::AnonymousUsing<'db>))] -#[visit(drive(&crate::cst::AnonymousVar<'db>))] -#[visit(drive(&crate::cst::AnonymousVoid<'db>))] -#[visit(drive(&crate::cst::AnonymousWhile<'db>))] -#[visit(drive(&crate::cst::AnonymousWith<'db>))] -#[visit(drive(&crate::cst::AnonymousYield<'db>))] -#[visit(drive(&crate::cst::Arguments<'db>))] -#[visit(drive(&crate::cst::ArgumentsChildren<'db>))] -#[visit(drive(&crate::cst::Array<'db>))] -#[visit(drive(&crate::cst::ArrayChildren<'db>))] -#[visit(drive(&crate::cst::ArrayPattern<'db>))] -#[visit(drive(&crate::cst::ArrayPatternChildren<'db>))] -#[visit(drive(&crate::cst::ArrayType<'db>))] -#[visit(drive(&crate::cst::ArrayTypeChildren<'db>))] -#[visit(drive(&crate::cst::ArrowFunction<'db>))] -#[visit(drive(&crate::cst::ArrowFunctionBody<'db>))] -#[visit(drive(&crate::cst::ArrowFunctionChildren<'db>))] -#[visit(drive(&crate::cst::ArrowFunctionReturnType<'db>))] -#[visit(drive(&crate::cst::AsExpression<'db>))] -#[visit(drive(&crate::cst::AsExpressionChildren<'db>))] -#[visit(drive(&crate::cst::Asserts<'db>))] -#[visit(drive(&crate::cst::AssertsAnnotation<'db>))] -#[visit(drive(&crate::cst::AssertsAnnotationChildren<'db>))] -#[visit(drive(&crate::cst::AssertsChildren<'db>))] -#[visit(drive(&crate::cst::AssignmentExpression<'db>))] -#[visit(drive(&crate::cst::AssignmentExpressionChildren<'db>))] -#[visit(drive(&crate::cst::AssignmentExpressionLeft<'db>))] -#[visit(drive(&crate::cst::AssignmentPattern<'db>))] -#[visit(drive(&crate::cst::AssignmentPatternChildren<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentExpression<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentExpressionChildren<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentExpressionLeft<'db>))] -#[visit(drive(&crate::cst::AugmentedAssignmentExpressionOperator<'db>))] -#[visit(drive(&crate::cst::AwaitExpression<'db>))] -#[visit(drive(&crate::cst::AwaitExpressionChildren<'db>))] -#[visit(drive(&crate::cst::BinaryExpression<'db>))] -#[visit(drive(&crate::cst::BinaryExpressionChildren<'db>))] -#[visit(drive(&crate::cst::BinaryExpressionLeft<'db>))] -#[visit(drive(&crate::cst::BinaryExpressionOperator<'db>))] -#[visit(drive(&crate::cst::BreakStatement<'db>))] -#[visit(drive(&crate::cst::BreakStatementChildren<'db>))] -#[visit(drive(&crate::cst::CallExpression<'db>))] -#[visit(drive(&crate::cst::CallExpressionArguments<'db>))] -#[visit(drive(&crate::cst::CallExpressionChildren<'db>))] -#[visit(drive(&crate::cst::CallExpressionFunction<'db>))] -#[visit(drive(&crate::cst::CallSignature<'db>))] -#[visit(drive(&crate::cst::CallSignatureChildren<'db>))] -#[visit(drive(&crate::cst::CallSignatureReturnType<'db>))] -#[visit(drive(&crate::cst::CatchClause<'db>))] -#[visit(drive(&crate::cst::CatchClauseChildren<'db>))] -#[visit(drive(&crate::cst::CatchClauseParameter<'db>))] -#[visit(drive(&crate::cst::Class<'db>))] -#[visit(drive(&crate::cst::ClassBody<'db>))] -#[visit(drive(&crate::cst::ClassBodyChildren<'db>))] -#[visit(drive(&crate::cst::ClassChildren<'db>))] -#[visit(drive(&crate::cst::ClassDeclaration<'db>))] -#[visit(drive(&crate::cst::ClassDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::ClassHeritage<'db>))] -#[visit(drive(&crate::cst::ClassHeritageChildren<'db>))] -#[visit(drive(&crate::cst::ClassStaticBlock<'db>))] -#[visit(drive(&crate::cst::ClassStaticBlockChildren<'db>))] -#[visit(drive(&crate::cst::Comment<'db>))] -#[visit(drive(&crate::cst::ComputedPropertyName<'db>))] -#[visit(drive(&crate::cst::ComputedPropertyNameChildren<'db>))] -#[visit(drive(&crate::cst::ConditionalType<'db>))] -#[visit(drive(&crate::cst::ConditionalTypeChildren<'db>))] -#[visit(drive(&crate::cst::Constraint<'db>))] -#[visit(drive(&crate::cst::ConstraintChildren<'db>))] -#[visit(drive(&crate::cst::ConstructSignature<'db>))] -#[visit(drive(&crate::cst::ConstructSignatureChildren<'db>))] -#[visit(drive(&crate::cst::ConstructorType<'db>))] -#[visit(drive(&crate::cst::ConstructorTypeChildren<'db>))] -#[visit(drive(&crate::cst::ContinueStatement<'db>))] -#[visit(drive(&crate::cst::ContinueStatementChildren<'db>))] -#[visit(drive(&crate::cst::DebuggerStatement<'db>))] -#[visit(drive(&crate::cst::Declaration<'db>))] -#[visit(drive(&crate::cst::Decorator<'db>))] -#[visit(drive(&crate::cst::DecoratorChildren<'db>))] -#[visit(drive(&crate::cst::DefaultType<'db>))] -#[visit(drive(&crate::cst::DefaultTypeChildren<'db>))] -#[visit(drive(&crate::cst::DoStatement<'db>))] -#[visit(drive(&crate::cst::DoStatementChildren<'db>))] -#[visit(drive(&crate::cst::ElseClause<'db>))] -#[visit(drive(&crate::cst::ElseClauseChildren<'db>))] -#[visit(drive(&crate::cst::EmptyStatement<'db>))] -#[visit(drive(&crate::cst::EnumAssignment<'db>))] -#[visit(drive(&crate::cst::EnumAssignmentChildren<'db>))] -#[visit(drive(&crate::cst::EnumAssignmentName<'db>))] -#[visit(drive(&crate::cst::EnumBody<'db>))] -#[visit(drive(&crate::cst::EnumBodyChildren<'db>))] -#[visit(drive(&crate::cst::EnumBodyName<'db>))] -#[visit(drive(&crate::cst::EnumDeclaration<'db>))] -#[visit(drive(&crate::cst::EnumDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::EscapeSequence<'db>))] -#[visit(drive(&crate::cst::ExistentialType<'db>))] -#[visit(drive(&crate::cst::ExportClause<'db>))] -#[visit(drive(&crate::cst::ExportClauseChildren<'db>))] -#[visit(drive(&crate::cst::ExportSpecifier<'db>))] -#[visit(drive(&crate::cst::ExportSpecifierAlias<'db>))] -#[visit(drive(&crate::cst::ExportSpecifierChildren<'db>))] -#[visit(drive(&crate::cst::ExportSpecifierName<'db>))] -#[visit(drive(&crate::cst::ExportStatement<'db>))] -#[visit(drive(&crate::cst::ExportStatementChildren<'db>))] -#[visit(drive(&crate::cst::Expression<'db>))] -#[visit(drive(&crate::cst::ExpressionStatement<'db>))] -#[visit(drive(&crate::cst::ExpressionStatementChildren<'db>))] -#[visit(drive(&crate::cst::ExtendsClause<'db>))] -#[visit(drive(&crate::cst::ExtendsClauseChildren<'db>))] -#[visit(drive(&crate::cst::ExtendsTypeClause<'db>))] -#[visit(drive(&crate::cst::ExtendsTypeClauseChildren<'db>))] -#[visit(drive(&crate::cst::ExtendsTypeClauseType<'db>))] -#[visit(drive(&crate::cst::False<'db>))] -#[visit(drive(&crate::cst::FinallyClause<'db>))] -#[visit(drive(&crate::cst::FinallyClauseChildren<'db>))] -#[visit(drive(&crate::cst::FlowMaybeType<'db>))] -#[visit(drive(&crate::cst::FlowMaybeTypeChildren<'db>))] -#[visit(drive(&crate::cst::ForInStatement<'db>))] -#[visit(drive(&crate::cst::ForInStatementChildren<'db>))] -#[visit(drive(&crate::cst::ForInStatementKind<'db>))] -#[visit(drive(&crate::cst::ForInStatementLeft<'db>))] -#[visit(drive(&crate::cst::ForInStatementOperator<'db>))] -#[visit(drive(&crate::cst::ForInStatementRight<'db>))] -#[visit(drive(&crate::cst::ForStatement<'db>))] -#[visit(drive(&crate::cst::ForStatementChildren<'db>))] -#[visit(drive(&crate::cst::ForStatementCondition<'db>))] -#[visit(drive(&crate::cst::ForStatementIncrement<'db>))] -#[visit(drive(&crate::cst::ForStatementInitializer<'db>))] -#[visit(drive(&crate::cst::FormalParameters<'db>))] -#[visit(drive(&crate::cst::FormalParametersChildren<'db>))] -#[visit(drive(&crate::cst::FunctionDeclaration<'db>))] -#[visit(drive(&crate::cst::FunctionDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::FunctionDeclarationReturnType<'db>))] -#[visit(drive(&crate::cst::FunctionExpression<'db>))] -#[visit(drive(&crate::cst::FunctionExpressionChildren<'db>))] -#[visit(drive(&crate::cst::FunctionExpressionReturnType<'db>))] -#[visit(drive(&crate::cst::FunctionSignatureChildren<'db>))] -#[visit(drive(&crate::cst::FunctionSignatureReturnType<'db>))] -#[visit(drive(&crate::cst::FunctionType<'db>))] -#[visit(drive(&crate::cst::FunctionTypeChildren<'db>))] -#[visit(drive(&crate::cst::FunctionTypeReturnType<'db>))] -#[visit(drive(&crate::cst::GeneratorFunction<'db>))] -#[visit(drive(&crate::cst::GeneratorFunctionChildren<'db>))] -#[visit(drive(&crate::cst::GeneratorFunctionDeclaration<'db>))] -#[visit(drive(&crate::cst::GeneratorFunctionDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::GeneratorFunctionDeclarationReturnType<'db>))] -#[visit(drive(&crate::cst::GeneratorFunctionReturnType<'db>))] -#[visit(drive(&crate::cst::GenericType<'db>))] -#[visit(drive(&crate::cst::GenericTypeChildren<'db>))] -#[visit(drive(&crate::cst::GenericTypeName<'db>))] -#[visit(drive(&crate::cst::HashBangLine<'db>))] -#[visit(drive(&crate::cst::HtmlComment<'db>))] -#[visit(drive(&crate::cst::Identifier<'db>))] -#[visit(drive(&crate::cst::IfStatement<'db>))] -#[visit(drive(&crate::cst::IfStatementChildren<'db>))] -#[visit(drive(&crate::cst::ImplementsClause<'db>))] -#[visit(drive(&crate::cst::ImplementsClauseChildren<'db>))] -#[visit(drive(&crate::cst::Import<'db>))] -#[visit(drive(&crate::cst::ImportAlias<'db>))] -#[visit(drive(&crate::cst::ImportAliasChildren<'db>))] -#[visit(drive(&crate::cst::ImportAttribute<'db>))] -#[visit(drive(&crate::cst::ImportAttributeChildren<'db>))] -#[visit(drive(&crate::cst::ImportClause<'db>))] -#[visit(drive(&crate::cst::ImportClauseChildren<'db>))] -#[visit(drive(&crate::cst::ImportRequireClause<'db>))] -#[visit(drive(&crate::cst::ImportRequireClauseChildren<'db>))] -#[visit(drive(&crate::cst::ImportSpecifier<'db>))] -#[visit(drive(&crate::cst::ImportSpecifierChildren<'db>))] -#[visit(drive(&crate::cst::ImportSpecifierName<'db>))] -#[visit(drive(&crate::cst::ImportStatement<'db>))] -#[visit(drive(&crate::cst::ImportStatementChildren<'db>))] -#[visit(drive(&crate::cst::IndexSignature<'db>))] -#[visit(drive(&crate::cst::IndexSignatureChildren<'db>))] -#[visit(drive(&crate::cst::IndexSignatureSign<'db>))] -#[visit(drive(&crate::cst::IndexSignatureType<'db>))] -#[visit(drive(&crate::cst::IndexTypeQuery<'db>))] -#[visit(drive(&crate::cst::IndexTypeQueryChildren<'db>))] -#[visit(drive(&crate::cst::InferType<'db>))] -#[visit(drive(&crate::cst::InferTypeChildren<'db>))] -#[visit(drive(&crate::cst::InstantiationExpression<'db>))] -#[visit(drive(&crate::cst::InstantiationExpressionChildren<'db>))] -#[visit(drive(&crate::cst::InstantiationExpressionFunction<'db>))] -#[visit(drive(&crate::cst::InterfaceBody<'db>))] -#[visit(drive(&crate::cst::InterfaceBodyChildren<'db>))] -#[visit(drive(&crate::cst::InterfaceDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::InternalModule<'db>))] -#[visit(drive(&crate::cst::InternalModuleChildren<'db>))] -#[visit(drive(&crate::cst::InternalModuleName<'db>))] -#[visit(drive(&crate::cst::IntersectionType<'db>))] -#[visit(drive(&crate::cst::IntersectionTypeChildren<'db>))] -#[visit(drive(&crate::cst::LabeledStatement<'db>))] -#[visit(drive(&crate::cst::LabeledStatementChildren<'db>))] -#[visit(drive(&crate::cst::LexicalDeclaration<'db>))] -#[visit(drive(&crate::cst::LexicalDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::LexicalDeclarationKind<'db>))] -#[visit(drive(&crate::cst::LiteralType<'db>))] -#[visit(drive(&crate::cst::LiteralTypeChildren<'db>))] -#[visit(drive(&crate::cst::LookupType<'db>))] -#[visit(drive(&crate::cst::LookupTypeChildren<'db>))] -#[visit(drive(&crate::cst::MappedTypeClause<'db>))] -#[visit(drive(&crate::cst::MappedTypeClauseChildren<'db>))] -#[visit(drive(&crate::cst::MemberExpression<'db>))] -#[visit(drive(&crate::cst::MemberExpressionChildren<'db>))] -#[visit(drive(&crate::cst::MemberExpressionObject<'db>))] -#[visit(drive(&crate::cst::MemberExpressionProperty<'db>))] -#[visit(drive(&crate::cst::MetaProperty<'db>))] -#[visit(drive(&crate::cst::MethodDefinition<'db>))] -#[visit(drive(&crate::cst::MethodDefinitionChildren<'db>))] -#[visit(drive(&crate::cst::MethodDefinitionName<'db>))] -#[visit(drive(&crate::cst::MethodDefinitionReturnType<'db>))] -#[visit(drive(&crate::cst::MethodSignature<'db>))] -#[visit(drive(&crate::cst::MethodSignatureChildren<'db>))] -#[visit(drive(&crate::cst::MethodSignatureName<'db>))] -#[visit(drive(&crate::cst::MethodSignatureReturnType<'db>))] -#[visit(drive(&crate::cst::ModuleChildren<'db>))] -#[visit(drive(&crate::cst::ModuleName<'db>))] -#[visit(drive(&crate::cst::NamedImports<'db>))] -#[visit(drive(&crate::cst::NamedImportsChildren<'db>))] -#[visit(drive(&crate::cst::NamespaceExport<'db>))] -#[visit(drive(&crate::cst::NamespaceExportChildren<'db>))] -#[visit(drive(&crate::cst::NamespaceImport<'db>))] -#[visit(drive(&crate::cst::NamespaceImportChildren<'db>))] -#[visit(drive(&crate::cst::NestedIdentifier<'db>))] -#[visit(drive(&crate::cst::NestedIdentifierChildren<'db>))] -#[visit(drive(&crate::cst::NestedIdentifierObject<'db>))] -#[visit(drive(&crate::cst::NestedTypeIdentifier<'db>))] -#[visit(drive(&crate::cst::NestedTypeIdentifierChildren<'db>))] -#[visit(drive(&crate::cst::NestedTypeIdentifierModule<'db>))] -#[visit(drive(&crate::cst::NewExpression<'db>))] -#[visit(drive(&crate::cst::NewExpressionChildren<'db>))] -#[visit(drive(&crate::cst::NonNullExpression<'db>))] -#[visit(drive(&crate::cst::NonNullExpressionChildren<'db>))] -#[visit(drive(&crate::cst::Null<'db>))] -#[visit(drive(&crate::cst::Number<'db>))] -#[visit(drive(&crate::cst::Object<'db>))] -#[visit(drive(&crate::cst::ObjectAssignmentPattern<'db>))] -#[visit(drive(&crate::cst::ObjectAssignmentPatternChildren<'db>))] -#[visit(drive(&crate::cst::ObjectAssignmentPatternLeft<'db>))] -#[visit(drive(&crate::cst::ObjectChildren<'db>))] -#[visit(drive(&crate::cst::ObjectPattern<'db>))] -#[visit(drive(&crate::cst::ObjectPatternChildren<'db>))] -#[visit(drive(&crate::cst::ObjectType<'db>))] -#[visit(drive(&crate::cst::ObjectTypeChildren<'db>))] -#[visit(drive(&crate::cst::OmittingTypeAnnotation<'db>))] -#[visit(drive(&crate::cst::OmittingTypeAnnotationChildren<'db>))] -#[visit(drive(&crate::cst::OptingTypeAnnotation<'db>))] -#[visit(drive(&crate::cst::OptingTypeAnnotationChildren<'db>))] -#[visit(drive(&crate::cst::OptionalChain<'db>))] -#[visit(drive(&crate::cst::OptionalParameter<'db>))] -#[visit(drive(&crate::cst::OptionalParameterChildren<'db>))] -#[visit(drive(&crate::cst::OptionalParameterPattern<'db>))] -#[visit(drive(&crate::cst::OptionalType<'db>))] -#[visit(drive(&crate::cst::OptionalTypeChildren<'db>))] -#[visit(drive(&crate::cst::OverrideModifier<'db>))] -#[visit(drive(&crate::cst::Pair<'db>))] -#[visit(drive(&crate::cst::PairChildren<'db>))] -#[visit(drive(&crate::cst::PairKey<'db>))] -#[visit(drive(&crate::cst::PairPattern<'db>))] -#[visit(drive(&crate::cst::PairPatternChildren<'db>))] -#[visit(drive(&crate::cst::PairPatternKey<'db>))] -#[visit(drive(&crate::cst::PairPatternValue<'db>))] -#[visit(drive(&crate::cst::ParenthesizedExpression<'db>))] -#[visit(drive(&crate::cst::ParenthesizedExpressionChildren<'db>))] -#[visit(drive(&crate::cst::ParenthesizedType<'db>))] -#[visit(drive(&crate::cst::ParenthesizedTypeChildren<'db>))] -#[visit(drive(&crate::cst::Pattern<'db>))] -#[visit(drive(&crate::cst::PredefinedType<'db>))] -#[visit(drive(&crate::cst::PrimaryExpression<'db>))] -#[visit(drive(&crate::cst::PrimaryType<'db>))] -#[visit(drive(&crate::cst::PrivatePropertyIdentifier<'db>))] -#[visit(drive(&crate::cst::Program<'db>))] -#[visit(drive(&crate::cst::ProgramChildren<'db>))] -#[visit(drive(&crate::cst::PropertyIdentifier<'db>))] -#[visit(drive(&crate::cst::PropertySignature<'db>))] -#[visit(drive(&crate::cst::PropertySignatureChildren<'db>))] -#[visit(drive(&crate::cst::PropertySignatureName<'db>))] -#[visit(drive(&crate::cst::PublicFieldDefinition<'db>))] -#[visit(drive(&crate::cst::PublicFieldDefinitionChildren<'db>))] -#[visit(drive(&crate::cst::PublicFieldDefinitionName<'db>))] -#[visit(drive(&crate::cst::ReadonlyType<'db>))] -#[visit(drive(&crate::cst::ReadonlyTypeChildren<'db>))] -#[visit(drive(&crate::cst::Regex<'db>))] -#[visit(drive(&crate::cst::RegexChildren<'db>))] -#[visit(drive(&crate::cst::RegexFlags<'db>))] -#[visit(drive(&crate::cst::RegexPattern<'db>))] -#[visit(drive(&crate::cst::RequiredParameter<'db>))] -#[visit(drive(&crate::cst::RequiredParameterChildren<'db>))] -#[visit(drive(&crate::cst::RequiredParameterName<'db>))] -#[visit(drive(&crate::cst::RequiredParameterPattern<'db>))] -#[visit(drive(&crate::cst::RestPattern<'db>))] -#[visit(drive(&crate::cst::RestPatternChildren<'db>))] -#[visit(drive(&crate::cst::RestType<'db>))] -#[visit(drive(&crate::cst::RestTypeChildren<'db>))] -#[visit(drive(&crate::cst::ReturnStatement<'db>))] -#[visit(drive(&crate::cst::ReturnStatementChildren<'db>))] -#[visit(drive(&crate::cst::SatisfiesExpression<'db>))] -#[visit(drive(&crate::cst::SatisfiesExpressionChildren<'db>))] -#[visit(drive(&crate::cst::SequenceExpression<'db>))] -#[visit(drive(&crate::cst::SequenceExpressionChildren<'db>))] -#[visit(drive(&crate::cst::ShorthandPropertyIdentifier<'db>))] -#[visit(drive(&crate::cst::ShorthandPropertyIdentifierPattern<'db>))] -#[visit(drive(&crate::cst::SpreadElement<'db>))] -#[visit(drive(&crate::cst::SpreadElementChildren<'db>))] -#[visit(drive(&crate::cst::Statement<'db>))] -#[visit(drive(&crate::cst::StatementBlock<'db>))] -#[visit(drive(&crate::cst::StatementBlockChildren<'db>))] -#[visit(drive(&crate::cst::StatementIdentifier<'db>))] -#[visit(drive(&crate::cst::String<'db>))] -#[visit(drive(&crate::cst::StringChildren<'db>))] -#[visit(drive(&crate::cst::StringFragment<'db>))] -#[visit(drive(&crate::cst::SubscriptExpression<'db>))] -#[visit(drive(&crate::cst::SubscriptExpressionChildren<'db>))] -#[visit(drive(&crate::cst::SubscriptExpressionIndex<'db>))] -#[visit(drive(&crate::cst::Super<'db>))] -#[visit(drive(&crate::cst::SwitchBody<'db>))] -#[visit(drive(&crate::cst::SwitchBodyChildren<'db>))] -#[visit(drive(&crate::cst::SwitchCase<'db>))] -#[visit(drive(&crate::cst::SwitchCaseChildren<'db>))] -#[visit(drive(&crate::cst::SwitchCaseValue<'db>))] -#[visit(drive(&crate::cst::SwitchDefault<'db>))] -#[visit(drive(&crate::cst::SwitchDefaultChildren<'db>))] -#[visit(drive(&crate::cst::SwitchStatement<'db>))] -#[visit(drive(&crate::cst::SwitchStatementChildren<'db>))] -#[visit(drive(&crate::cst::TemplateLiteralType<'db>))] -#[visit(drive(&crate::cst::TemplateLiteralTypeChildren<'db>))] -#[visit(drive(&crate::cst::TemplateString<'db>))] -#[visit(drive(&crate::cst::TemplateStringChildren<'db>))] -#[visit(drive(&crate::cst::TemplateSubstitution<'db>))] -#[visit(drive(&crate::cst::TemplateSubstitutionChildren<'db>))] -#[visit(drive(&crate::cst::TemplateType<'db>))] -#[visit(drive(&crate::cst::TemplateTypeChildren<'db>))] -#[visit(drive(&crate::cst::TernaryExpression<'db>))] -#[visit(drive(&crate::cst::TernaryExpressionChildren<'db>))] -#[visit(drive(&crate::cst::This<'db>))] -#[visit(drive(&crate::cst::ThisType<'db>))] -#[visit(drive(&crate::cst::ThrowStatement<'db>))] -#[visit(drive(&crate::cst::ThrowStatementChildren<'db>))] -#[visit(drive(&crate::cst::True<'db>))] -#[visit(drive(&crate::cst::TryStatement<'db>))] -#[visit(drive(&crate::cst::TryStatementChildren<'db>))] -#[visit(drive(&crate::cst::TupleType<'db>))] -#[visit(drive(&crate::cst::TupleTypeChildren<'db>))] -#[visit(drive(&crate::cst::Type<'db>))] -#[visit(drive(&crate::cst::TypeAliasDeclaration<'db>))] -#[visit(drive(&crate::cst::TypeAliasDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::TypeAnnotation<'db>))] -#[visit(drive(&crate::cst::TypeAnnotationChildren<'db>))] -#[visit(drive(&crate::cst::TypeArguments<'db>))] -#[visit(drive(&crate::cst::TypeArgumentsChildren<'db>))] -#[visit(drive(&crate::cst::TypeAssertion<'db>))] -#[visit(drive(&crate::cst::TypeAssertionChildren<'db>))] -#[visit(drive(&crate::cst::TypeIdentifier<'db>))] -#[visit(drive(&crate::cst::TypeParameter<'db>))] -#[visit(drive(&crate::cst::TypeParameterChildren<'db>))] -#[visit(drive(&crate::cst::TypeParameters<'db>))] -#[visit(drive(&crate::cst::TypeParametersChildren<'db>))] -#[visit(drive(&crate::cst::TypePredicate<'db>))] -#[visit(drive(&crate::cst::TypePredicateAnnotation<'db>))] -#[visit(drive(&crate::cst::TypePredicateAnnotationChildren<'db>))] -#[visit(drive(&crate::cst::TypePredicateChildren<'db>))] -#[visit(drive(&crate::cst::TypePredicateName<'db>))] -#[visit(drive(&crate::cst::TypeQuery<'db>))] -#[visit(drive(&crate::cst::TypeQueryChildren<'db>))] -#[visit(drive(&crate::cst::UnaryExpression<'db>))] -#[visit(drive(&crate::cst::UnaryExpressionArgument<'db>))] -#[visit(drive(&crate::cst::UnaryExpressionChildren<'db>))] -#[visit(drive(&crate::cst::UnaryExpressionOperator<'db>))] -#[visit(drive(&crate::cst::Undefined<'db>))] -#[visit(drive(&crate::cst::UnionType<'db>))] -#[visit(drive(&crate::cst::UnionTypeChildren<'db>))] -#[visit(drive(&crate::cst::UpdateExpression<'db>))] -#[visit(drive(&crate::cst::UpdateExpressionChildren<'db>))] -#[visit(drive(&crate::cst::UpdateExpressionOperator<'db>))] -#[visit(drive(&crate::cst::VariableDeclaration<'db>))] -#[visit(drive(&crate::cst::VariableDeclarationChildren<'db>))] -#[visit(drive(&crate::cst::VariableDeclarator<'db>))] -#[visit(drive(&crate::cst::VariableDeclaratorChildren<'db>))] -#[visit(drive(&crate::cst::VariableDeclaratorName<'db>))] -#[visit(drive(&crate::cst::WhileStatement<'db>))] -#[visit(drive(&crate::cst::WhileStatementChildren<'db>))] -#[visit(drive(&crate::cst::WithStatement<'db>))] -#[visit(drive(&crate::cst::WithStatementChildren<'db>))] -#[visit(drive(&crate::cst::YieldExpression<'db>))] -#[visit(drive(&crate::cst::YieldExpressionChildren<'db>))] -#[visit(drive(&crate::cst::AbstractClassDeclaration<'db>))] -#[visit(drive(&crate::cst::AbstractMethodSignature<'db>))] -#[visit(drive(&crate::cst::FunctionSignature<'db>))] -#[visit(drive(&crate::cst::InterfaceDeclaration<'db>))] -#[visit(drive(&crate::cst::Module<'db>))] -#[visit(drive(crate::cst::AbstractClassDeclarationChildren<'db>))] -#[visit(drive(crate::cst::AbstractMethodSignatureChildren<'db>))] -#[visit(drive(crate::cst::AbstractMethodSignatureName<'db>))] -#[visit(drive(crate::cst::AbstractMethodSignatureReturnType<'db>))] -#[visit(drive(crate::cst::AccessibilityModifier<'db>))] -#[visit(drive(crate::cst::AddingTypeAnnotation<'db>))] -#[visit(drive(crate::cst::AddingTypeAnnotationChildren<'db>))] -#[visit(drive(crate::cst::AmbientDeclaration<'db>))] -#[visit(drive(crate::cst::AmbientDeclarationChildren<'db>))] -#[visit(drive(crate::cst::AnonymousAbstract<'db>))] -#[visit(drive(crate::cst::AnonymousAccessor<'db>))] -#[visit(drive(crate::cst::AnonymousAmpersand<'db>))] -#[visit(drive(crate::cst::AnonymousAmpersandAmpersand<'db>))] -#[visit(drive(crate::cst::AnonymousAmpersandAmpersandEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAmpersandEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAny<'db>))] -#[visit(drive(crate::cst::AnonymousAs<'db>))] -#[visit(drive(crate::cst::AnonymousAssert<'db>))] -#[visit(drive(crate::cst::AnonymousAsserts<'db>))] -#[visit(drive(crate::cst::AnonymousAsterisk<'db>))] -#[visit(drive(crate::cst::AnonymousAsteriskAsterisk<'db>))] -#[visit(drive(crate::cst::AnonymousAsteriskAsteriskEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAsteriskEquals<'db>))] -#[visit(drive(crate::cst::AnonymousAsync<'db>))] -#[visit(drive(crate::cst::AnonymousAt<'db>))] -#[visit(drive(crate::cst::AnonymousAwait<'db>))] -#[visit(drive(crate::cst::AnonymousBacktick<'db>))] -#[visit(drive(crate::cst::AnonymousBang<'db>))] -#[visit(drive(crate::cst::AnonymousBangEquals<'db>))] -#[visit(drive(crate::cst::AnonymousBangEqualsEquals<'db>))] -#[visit(drive(crate::cst::AnonymousBoolean<'db>))] -#[visit(drive(crate::cst::AnonymousBreak<'db>))] -#[visit(drive(crate::cst::AnonymousCaret<'db>))] -#[visit(drive(crate::cst::AnonymousCaretEquals<'db>))] -#[visit(drive(crate::cst::AnonymousCase<'db>))] -#[visit(drive(crate::cst::AnonymousCatch<'db>))] -#[visit(drive(crate::cst::AnonymousClass<'db>))] -#[visit(drive(crate::cst::AnonymousCloseBrace<'db>))] -#[visit(drive(crate::cst::AnonymousCloseBracket<'db>))] -#[visit(drive(crate::cst::AnonymousCloseParen<'db>))] -#[visit(drive(crate::cst::AnonymousColon<'db>))] -#[visit(drive(crate::cst::AnonymousComma<'db>))] -#[visit(drive(crate::cst::AnonymousConst<'db>))] -#[visit(drive(crate::cst::AnonymousContinue<'db>))] -#[visit(drive(crate::cst::AnonymousDebugger<'db>))] -#[visit(drive(crate::cst::AnonymousDeclare<'db>))] -#[visit(drive(crate::cst::AnonymousDefault<'db>))] -#[visit(drive(crate::cst::AnonymousDelete<'db>))] -#[visit(drive(crate::cst::AnonymousDo<'db>))] -#[visit(drive(crate::cst::AnonymousDollarOpenBrace<'db>))] -#[visit(drive(crate::cst::AnonymousDot<'db>))] -#[visit(drive(crate::cst::AnonymousDotDotDot<'db>))] -#[visit(drive(crate::cst::AnonymousDoubleQuote<'db>))] -#[visit(drive(crate::cst::AnonymousElse<'db>))] -#[visit(drive(crate::cst::AnonymousEnum<'db>))] -#[visit(drive(crate::cst::AnonymousEquals<'db>))] -#[visit(drive(crate::cst::AnonymousEqualsEquals<'db>))] -#[visit(drive(crate::cst::AnonymousEqualsEqualsEquals<'db>))] -#[visit(drive(crate::cst::AnonymousEqualsGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousExport<'db>))] -#[visit(drive(crate::cst::AnonymousExtends<'db>))] -#[visit(drive(crate::cst::AnonymousFinally<'db>))] -#[visit(drive(crate::cst::AnonymousFor<'db>))] -#[visit(drive(crate::cst::AnonymousFrom<'db>))] -#[visit(drive(crate::cst::AnonymousFunction<'db>))] -#[visit(drive(crate::cst::AnonymousGet<'db>))] -#[visit(drive(crate::cst::AnonymousGlobal<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanGreaterThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanGreaterThanGreaterThan<'db>))] -#[visit(drive(crate::cst::AnonymousGreaterThanGreaterThanGreaterThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousIf<'db>))] -#[visit(drive(crate::cst::AnonymousImplements<'db>))] -#[visit(drive(crate::cst::AnonymousImport<'db>))] -#[visit(drive(crate::cst::AnonymousIn<'db>))] -#[visit(drive(crate::cst::AnonymousInfer<'db>))] -#[visit(drive(crate::cst::AnonymousInstanceof<'db>))] -#[visit(drive(crate::cst::AnonymousInterface<'db>))] -#[visit(drive(crate::cst::AnonymousIs<'db>))] -#[visit(drive(crate::cst::AnonymousKeyof<'db>))] -#[visit(drive(crate::cst::AnonymousLessThan<'db>))] -#[visit(drive(crate::cst::AnonymousLessThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousLessThanLessThan<'db>))] -#[visit(drive(crate::cst::AnonymousLessThanLessThanEquals<'db>))] -#[visit(drive(crate::cst::AnonymousLet<'db>))] -#[visit(drive(crate::cst::AnonymousMeta<'db>))] -#[visit(drive(crate::cst::AnonymousMinus<'db>))] -#[visit(drive(crate::cst::AnonymousMinusEquals<'db>))] -#[visit(drive(crate::cst::AnonymousMinusMinus<'db>))] -#[visit(drive(crate::cst::AnonymousMinusQuestionMarkColon<'db>))] -#[visit(drive(crate::cst::AnonymousModule<'db>))] -#[visit(drive(crate::cst::AnonymousNamespace<'db>))] -#[visit(drive(crate::cst::AnonymousNever<'db>))] -#[visit(drive(crate::cst::AnonymousNew<'db>))] -#[visit(drive(crate::cst::AnonymousNumber<'db>))] -#[visit(drive(crate::cst::AnonymousObject<'db>))] -#[visit(drive(crate::cst::AnonymousOf<'db>))] -#[visit(drive(crate::cst::AnonymousOpenBrace<'db>))] -#[visit(drive(crate::cst::AnonymousOpenBracePipe<'db>))] -#[visit(drive(crate::cst::AnonymousOpenBracket<'db>))] -#[visit(drive(crate::cst::AnonymousOpenParen<'db>))] -#[visit(drive(crate::cst::AnonymousOverride<'db>))] -#[visit(drive(crate::cst::AnonymousPercent<'db>))] -#[visit(drive(crate::cst::AnonymousPercentEquals<'db>))] -#[visit(drive(crate::cst::AnonymousPipe<'db>))] -#[visit(drive(crate::cst::AnonymousPipeCloseBrace<'db>))] -#[visit(drive(crate::cst::AnonymousPipeEquals<'db>))] -#[visit(drive(crate::cst::AnonymousPipePipe<'db>))] -#[visit(drive(crate::cst::AnonymousPipePipeEquals<'db>))] -#[visit(drive(crate::cst::AnonymousPlus<'db>))] -#[visit(drive(crate::cst::AnonymousPlusEquals<'db>))] -#[visit(drive(crate::cst::AnonymousPlusPlus<'db>))] -#[visit(drive(crate::cst::AnonymousPlusQuestionMarkColon<'db>))] -#[visit(drive(crate::cst::AnonymousPrivate<'db>))] -#[visit(drive(crate::cst::AnonymousProtected<'db>))] -#[visit(drive(crate::cst::AnonymousPublic<'db>))] -#[visit(drive(crate::cst::AnonymousQuestionMark<'db>))] -#[visit(drive(crate::cst::AnonymousQuestionMarkColon<'db>))] -#[visit(drive(crate::cst::AnonymousQuestionMarkDot<'db>))] -#[visit(drive(crate::cst::AnonymousQuestionMarkQuestionMark<'db>))] -#[visit(drive(crate::cst::AnonymousQuestionMarkQuestionMarkEquals<'db>))] -#[visit(drive(crate::cst::AnonymousReadonly<'db>))] -#[visit(drive(crate::cst::AnonymousRequire<'db>))] -#[visit(drive(crate::cst::AnonymousReturn<'db>))] -#[visit(drive(crate::cst::AnonymousSatisfies<'db>))] -#[visit(drive(crate::cst::AnonymousSemicolon<'db>))] -#[visit(drive(crate::cst::AnonymousSet<'db>))] -#[visit(drive(crate::cst::AnonymousSingleQuote<'db>))] -#[visit(drive(crate::cst::AnonymousSlash<'db>))] -#[visit(drive(crate::cst::AnonymousSlashEquals<'db>))] -#[visit(drive(crate::cst::AnonymousStatic<'db>))] -#[visit(drive(crate::cst::AnonymousString<'db>))] -#[visit(drive(crate::cst::AnonymousSwitch<'db>))] -#[visit(drive(crate::cst::AnonymousSymbol<'db>))] -#[visit(drive(crate::cst::AnonymousTarget<'db>))] -#[visit(drive(crate::cst::AnonymousThrow<'db>))] -#[visit(drive(crate::cst::AnonymousTilde<'db>))] -#[visit(drive(crate::cst::AnonymousTry<'db>))] -#[visit(drive(crate::cst::AnonymousType<'db>))] -#[visit(drive(crate::cst::AnonymousTypeof<'db>))] -#[visit(drive(crate::cst::AnonymousUniqueSymbol<'db>))] -#[visit(drive(crate::cst::AnonymousUnknown<'db>))] -#[visit(drive(crate::cst::AnonymousUsing<'db>))] -#[visit(drive(crate::cst::AnonymousVar<'db>))] -#[visit(drive(crate::cst::AnonymousVoid<'db>))] -#[visit(drive(crate::cst::AnonymousWhile<'db>))] -#[visit(drive(crate::cst::AnonymousWith<'db>))] -#[visit(drive(crate::cst::AnonymousYield<'db>))] -#[visit(drive(crate::cst::Arguments<'db>))] -#[visit(drive(crate::cst::ArgumentsChildren<'db>))] -#[visit(drive(crate::cst::Array<'db>))] -#[visit(drive(crate::cst::ArrayChildren<'db>))] -#[visit(drive(crate::cst::ArrayPattern<'db>))] -#[visit(drive(crate::cst::ArrayPatternChildren<'db>))] -#[visit(drive(crate::cst::ArrayType<'db>))] -#[visit(drive(crate::cst::ArrayTypeChildren<'db>))] -#[visit(drive(crate::cst::ArrowFunction<'db>))] -#[visit(drive(crate::cst::ArrowFunctionBody<'db>))] -#[visit(drive(crate::cst::ArrowFunctionChildren<'db>))] -#[visit(drive(crate::cst::ArrowFunctionReturnType<'db>))] -#[visit(drive(crate::cst::AsExpression<'db>))] -#[visit(drive(crate::cst::AsExpressionChildren<'db>))] -#[visit(drive(crate::cst::Asserts<'db>))] -#[visit(drive(crate::cst::AssertsAnnotation<'db>))] -#[visit(drive(crate::cst::AssertsAnnotationChildren<'db>))] -#[visit(drive(crate::cst::AssertsChildren<'db>))] -#[visit(drive(crate::cst::AssignmentExpression<'db>))] -#[visit(drive(crate::cst::AssignmentExpressionChildren<'db>))] -#[visit(drive(crate::cst::AssignmentExpressionLeft<'db>))] -#[visit(drive(crate::cst::AssignmentPattern<'db>))] -#[visit(drive(crate::cst::AssignmentPatternChildren<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentExpression<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentExpressionChildren<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentExpressionLeft<'db>))] -#[visit(drive(crate::cst::AugmentedAssignmentExpressionOperator<'db>))] -#[visit(drive(crate::cst::AwaitExpression<'db>))] -#[visit(drive(crate::cst::AwaitExpressionChildren<'db>))] -#[visit(drive(crate::cst::BinaryExpression<'db>))] -#[visit(drive(crate::cst::BinaryExpressionChildren<'db>))] -#[visit(drive(crate::cst::BinaryExpressionLeft<'db>))] -#[visit(drive(crate::cst::BinaryExpressionOperator<'db>))] -#[visit(drive(crate::cst::BreakStatement<'db>))] -#[visit(drive(crate::cst::BreakStatementChildren<'db>))] -#[visit(drive(crate::cst::CallExpression<'db>))] -#[visit(drive(crate::cst::CallExpressionArguments<'db>))] -#[visit(drive(crate::cst::CallExpressionChildren<'db>))] -#[visit(drive(crate::cst::CallExpressionFunction<'db>))] -#[visit(drive(crate::cst::CallSignature<'db>))] -#[visit(drive(crate::cst::CallSignatureChildren<'db>))] -#[visit(drive(crate::cst::CallSignatureReturnType<'db>))] -#[visit(drive(crate::cst::CatchClause<'db>))] -#[visit(drive(crate::cst::CatchClauseChildren<'db>))] -#[visit(drive(crate::cst::CatchClauseParameter<'db>))] -#[visit(drive(crate::cst::Class<'db>))] -#[visit(drive(crate::cst::ClassBody<'db>))] -#[visit(drive(crate::cst::ClassBodyChildren<'db>))] -#[visit(drive(crate::cst::ClassChildren<'db>))] -#[visit(drive(crate::cst::ClassDeclaration<'db>))] -#[visit(drive(crate::cst::ClassDeclarationChildren<'db>))] -#[visit(drive(crate::cst::ClassHeritage<'db>))] -#[visit(drive(crate::cst::ClassHeritageChildren<'db>))] -#[visit(drive(crate::cst::ClassStaticBlock<'db>))] -#[visit(drive(crate::cst::ClassStaticBlockChildren<'db>))] -#[visit(drive(crate::cst::Comment<'db>))] -#[visit(drive(crate::cst::ComputedPropertyName<'db>))] -#[visit(drive(crate::cst::ComputedPropertyNameChildren<'db>))] -#[visit(drive(crate::cst::ConditionalType<'db>))] -#[visit(drive(crate::cst::ConditionalTypeChildren<'db>))] -#[visit(drive(crate::cst::Constraint<'db>))] -#[visit(drive(crate::cst::ConstraintChildren<'db>))] -#[visit(drive(crate::cst::ConstructSignature<'db>))] -#[visit(drive(crate::cst::ConstructSignatureChildren<'db>))] -#[visit(drive(crate::cst::ConstructorType<'db>))] -#[visit(drive(crate::cst::ConstructorTypeChildren<'db>))] -#[visit(drive(crate::cst::ContinueStatement<'db>))] -#[visit(drive(crate::cst::ContinueStatementChildren<'db>))] -#[visit(drive(crate::cst::DebuggerStatement<'db>))] -#[visit(drive(crate::cst::Declaration<'db>))] -#[visit(drive(crate::cst::Decorator<'db>))] -#[visit(drive(crate::cst::DecoratorChildren<'db>))] -#[visit(drive(crate::cst::DefaultType<'db>))] -#[visit(drive(crate::cst::DefaultTypeChildren<'db>))] -#[visit(drive(crate::cst::DoStatement<'db>))] -#[visit(drive(crate::cst::DoStatementChildren<'db>))] -#[visit(drive(crate::cst::ElseClause<'db>))] -#[visit(drive(crate::cst::ElseClauseChildren<'db>))] -#[visit(drive(crate::cst::EmptyStatement<'db>))] -#[visit(drive(crate::cst::EnumAssignment<'db>))] -#[visit(drive(crate::cst::EnumAssignmentChildren<'db>))] -#[visit(drive(crate::cst::EnumAssignmentName<'db>))] -#[visit(drive(crate::cst::EnumBody<'db>))] -#[visit(drive(crate::cst::EnumBodyChildren<'db>))] -#[visit(drive(crate::cst::EnumBodyName<'db>))] -#[visit(drive(crate::cst::EnumDeclaration<'db>))] -#[visit(drive(crate::cst::EnumDeclarationChildren<'db>))] -#[visit(drive(crate::cst::EscapeSequence<'db>))] -#[visit(drive(crate::cst::ExistentialType<'db>))] -#[visit(drive(crate::cst::ExportClause<'db>))] -#[visit(drive(crate::cst::ExportClauseChildren<'db>))] -#[visit(drive(crate::cst::ExportSpecifier<'db>))] -#[visit(drive(crate::cst::ExportSpecifierAlias<'db>))] -#[visit(drive(crate::cst::ExportSpecifierChildren<'db>))] -#[visit(drive(crate::cst::ExportSpecifierName<'db>))] -#[visit(drive(crate::cst::ExportStatement<'db>))] -#[visit(drive(crate::cst::ExportStatementChildren<'db>))] -#[visit(drive(crate::cst::Expression<'db>))] -#[visit(drive(crate::cst::ExpressionStatement<'db>))] -#[visit(drive(crate::cst::ExpressionStatementChildren<'db>))] -#[visit(drive(crate::cst::ExtendsClause<'db>))] -#[visit(drive(crate::cst::ExtendsClauseChildren<'db>))] -#[visit(drive(crate::cst::ExtendsTypeClause<'db>))] -#[visit(drive(crate::cst::ExtendsTypeClauseChildren<'db>))] -#[visit(drive(crate::cst::ExtendsTypeClauseType<'db>))] -#[visit(drive(crate::cst::False<'db>))] -#[visit(drive(crate::cst::FinallyClause<'db>))] -#[visit(drive(crate::cst::FinallyClauseChildren<'db>))] -#[visit(drive(crate::cst::FlowMaybeType<'db>))] -#[visit(drive(crate::cst::FlowMaybeTypeChildren<'db>))] -#[visit(drive(crate::cst::ForInStatement<'db>))] -#[visit(drive(crate::cst::ForInStatementChildren<'db>))] -#[visit(drive(crate::cst::ForInStatementKind<'db>))] -#[visit(drive(crate::cst::ForInStatementLeft<'db>))] -#[visit(drive(crate::cst::ForInStatementOperator<'db>))] -#[visit(drive(crate::cst::ForInStatementRight<'db>))] -#[visit(drive(crate::cst::ForStatement<'db>))] -#[visit(drive(crate::cst::ForStatementChildren<'db>))] -#[visit(drive(crate::cst::ForStatementCondition<'db>))] -#[visit(drive(crate::cst::ForStatementIncrement<'db>))] -#[visit(drive(crate::cst::ForStatementInitializer<'db>))] -#[visit(drive(crate::cst::FormalParameters<'db>))] -#[visit(drive(crate::cst::FormalParametersChildren<'db>))] -#[visit(drive(crate::cst::FunctionDeclaration<'db>))] -#[visit(drive(crate::cst::FunctionDeclarationChildren<'db>))] -#[visit(drive(crate::cst::FunctionDeclarationReturnType<'db>))] -#[visit(drive(crate::cst::FunctionExpression<'db>))] -#[visit(drive(crate::cst::FunctionExpressionChildren<'db>))] -#[visit(drive(crate::cst::FunctionExpressionReturnType<'db>))] -#[visit(drive(crate::cst::FunctionSignatureChildren<'db>))] -#[visit(drive(crate::cst::FunctionSignatureReturnType<'db>))] -#[visit(drive(crate::cst::FunctionType<'db>))] -#[visit(drive(crate::cst::FunctionTypeChildren<'db>))] -#[visit(drive(crate::cst::FunctionTypeReturnType<'db>))] -#[visit(drive(crate::cst::GeneratorFunction<'db>))] -#[visit(drive(crate::cst::GeneratorFunctionChildren<'db>))] -#[visit(drive(crate::cst::GeneratorFunctionDeclaration<'db>))] -#[visit(drive(crate::cst::GeneratorFunctionDeclarationChildren<'db>))] -#[visit(drive(crate::cst::GeneratorFunctionDeclarationReturnType<'db>))] -#[visit(drive(crate::cst::GeneratorFunctionReturnType<'db>))] -#[visit(drive(crate::cst::GenericType<'db>))] -#[visit(drive(crate::cst::GenericTypeChildren<'db>))] -#[visit(drive(crate::cst::GenericTypeName<'db>))] -#[visit(drive(crate::cst::HashBangLine<'db>))] -#[visit(drive(crate::cst::HtmlComment<'db>))] -#[visit(drive(crate::cst::Identifier<'db>))] -#[visit(drive(crate::cst::IfStatement<'db>))] -#[visit(drive(crate::cst::IfStatementChildren<'db>))] -#[visit(drive(crate::cst::ImplementsClause<'db>))] -#[visit(drive(crate::cst::ImplementsClauseChildren<'db>))] -#[visit(drive(crate::cst::Import<'db>))] -#[visit(drive(crate::cst::ImportAlias<'db>))] -#[visit(drive(crate::cst::ImportAliasChildren<'db>))] -#[visit(drive(crate::cst::ImportAttribute<'db>))] -#[visit(drive(crate::cst::ImportAttributeChildren<'db>))] -#[visit(drive(crate::cst::ImportClause<'db>))] -#[visit(drive(crate::cst::ImportClauseChildren<'db>))] -#[visit(drive(crate::cst::ImportRequireClause<'db>))] -#[visit(drive(crate::cst::ImportRequireClauseChildren<'db>))] -#[visit(drive(crate::cst::ImportSpecifier<'db>))] -#[visit(drive(crate::cst::ImportSpecifierChildren<'db>))] -#[visit(drive(crate::cst::ImportSpecifierName<'db>))] -#[visit(drive(crate::cst::ImportStatement<'db>))] -#[visit(drive(crate::cst::ImportStatementChildren<'db>))] -#[visit(drive(crate::cst::IndexSignature<'db>))] -#[visit(drive(crate::cst::IndexSignatureChildren<'db>))] -#[visit(drive(crate::cst::IndexSignatureSign<'db>))] -#[visit(drive(crate::cst::IndexSignatureType<'db>))] -#[visit(drive(crate::cst::IndexTypeQuery<'db>))] -#[visit(drive(crate::cst::IndexTypeQueryChildren<'db>))] -#[visit(drive(crate::cst::InferType<'db>))] -#[visit(drive(crate::cst::InferTypeChildren<'db>))] -#[visit(drive(crate::cst::InstantiationExpression<'db>))] -#[visit(drive(crate::cst::InstantiationExpressionChildren<'db>))] -#[visit(drive(crate::cst::InstantiationExpressionFunction<'db>))] -#[visit(drive(crate::cst::InterfaceBody<'db>))] -#[visit(drive(crate::cst::InterfaceBodyChildren<'db>))] -#[visit(drive(crate::cst::InterfaceDeclarationChildren<'db>))] -#[visit(drive(crate::cst::InternalModule<'db>))] -#[visit(drive(crate::cst::InternalModuleChildren<'db>))] -#[visit(drive(crate::cst::InternalModuleName<'db>))] -#[visit(drive(crate::cst::IntersectionType<'db>))] -#[visit(drive(crate::cst::IntersectionTypeChildren<'db>))] -#[visit(drive(crate::cst::LabeledStatement<'db>))] -#[visit(drive(crate::cst::LabeledStatementChildren<'db>))] -#[visit(drive(crate::cst::LexicalDeclaration<'db>))] -#[visit(drive(crate::cst::LexicalDeclarationChildren<'db>))] -#[visit(drive(crate::cst::LexicalDeclarationKind<'db>))] -#[visit(drive(crate::cst::LiteralType<'db>))] -#[visit(drive(crate::cst::LiteralTypeChildren<'db>))] -#[visit(drive(crate::cst::LookupType<'db>))] -#[visit(drive(crate::cst::LookupTypeChildren<'db>))] -#[visit(drive(crate::cst::MappedTypeClause<'db>))] -#[visit(drive(crate::cst::MappedTypeClauseChildren<'db>))] -#[visit(drive(crate::cst::MemberExpression<'db>))] -#[visit(drive(crate::cst::MemberExpressionChildren<'db>))] -#[visit(drive(crate::cst::MemberExpressionObject<'db>))] -#[visit(drive(crate::cst::MemberExpressionProperty<'db>))] -#[visit(drive(crate::cst::MetaProperty<'db>))] -#[visit(drive(crate::cst::MethodDefinition<'db>))] -#[visit(drive(crate::cst::MethodDefinitionChildren<'db>))] -#[visit(drive(crate::cst::MethodDefinitionName<'db>))] -#[visit(drive(crate::cst::MethodDefinitionReturnType<'db>))] -#[visit(drive(crate::cst::MethodSignature<'db>))] -#[visit(drive(crate::cst::MethodSignatureChildren<'db>))] -#[visit(drive(crate::cst::MethodSignatureName<'db>))] -#[visit(drive(crate::cst::MethodSignatureReturnType<'db>))] -#[visit(drive(crate::cst::ModuleChildren<'db>))] -#[visit(drive(crate::cst::ModuleName<'db>))] -#[visit(drive(crate::cst::NamedImports<'db>))] -#[visit(drive(crate::cst::NamedImportsChildren<'db>))] -#[visit(drive(crate::cst::NamespaceExport<'db>))] -#[visit(drive(crate::cst::NamespaceExportChildren<'db>))] -#[visit(drive(crate::cst::NamespaceImport<'db>))] -#[visit(drive(crate::cst::NamespaceImportChildren<'db>))] -#[visit(drive(crate::cst::NestedIdentifier<'db>))] -#[visit(drive(crate::cst::NestedIdentifierChildren<'db>))] -#[visit(drive(crate::cst::NestedIdentifierObject<'db>))] -#[visit(drive(crate::cst::NestedTypeIdentifier<'db>))] -#[visit(drive(crate::cst::NestedTypeIdentifierChildren<'db>))] -#[visit(drive(crate::cst::NestedTypeIdentifierModule<'db>))] -#[visit(drive(crate::cst::NewExpression<'db>))] -#[visit(drive(crate::cst::NewExpressionChildren<'db>))] -#[visit(drive(crate::cst::NonNullExpression<'db>))] -#[visit(drive(crate::cst::NonNullExpressionChildren<'db>))] -#[visit(drive(crate::cst::Null<'db>))] -#[visit(drive(crate::cst::Number<'db>))] -#[visit(drive(crate::cst::Object<'db>))] -#[visit(drive(crate::cst::ObjectAssignmentPattern<'db>))] -#[visit(drive(crate::cst::ObjectAssignmentPatternChildren<'db>))] -#[visit(drive(crate::cst::ObjectAssignmentPatternLeft<'db>))] -#[visit(drive(crate::cst::ObjectChildren<'db>))] -#[visit(drive(crate::cst::ObjectPattern<'db>))] -#[visit(drive(crate::cst::ObjectPatternChildren<'db>))] -#[visit(drive(crate::cst::ObjectType<'db>))] -#[visit(drive(crate::cst::ObjectTypeChildren<'db>))] -#[visit(drive(crate::cst::OmittingTypeAnnotation<'db>))] -#[visit(drive(crate::cst::OmittingTypeAnnotationChildren<'db>))] -#[visit(drive(crate::cst::OptingTypeAnnotation<'db>))] -#[visit(drive(crate::cst::OptingTypeAnnotationChildren<'db>))] -#[visit(drive(crate::cst::OptionalChain<'db>))] -#[visit(drive(crate::cst::OptionalParameter<'db>))] -#[visit(drive(crate::cst::OptionalParameterChildren<'db>))] -#[visit(drive(crate::cst::OptionalParameterPattern<'db>))] -#[visit(drive(crate::cst::OptionalType<'db>))] -#[visit(drive(crate::cst::OptionalTypeChildren<'db>))] -#[visit(drive(crate::cst::OverrideModifier<'db>))] -#[visit(drive(crate::cst::Pair<'db>))] -#[visit(drive(crate::cst::PairChildren<'db>))] -#[visit(drive(crate::cst::PairKey<'db>))] -#[visit(drive(crate::cst::PairPattern<'db>))] -#[visit(drive(crate::cst::PairPatternChildren<'db>))] -#[visit(drive(crate::cst::PairPatternKey<'db>))] -#[visit(drive(crate::cst::PairPatternValue<'db>))] -#[visit(drive(crate::cst::ParenthesizedExpression<'db>))] -#[visit(drive(crate::cst::ParenthesizedExpressionChildren<'db>))] -#[visit(drive(crate::cst::ParenthesizedType<'db>))] -#[visit(drive(crate::cst::ParenthesizedTypeChildren<'db>))] -#[visit(drive(crate::cst::Pattern<'db>))] -#[visit(drive(crate::cst::PredefinedType<'db>))] -#[visit(drive(crate::cst::PrimaryExpression<'db>))] -#[visit(drive(crate::cst::PrimaryType<'db>))] -#[visit(drive(crate::cst::PrivatePropertyIdentifier<'db>))] -#[visit(drive(crate::cst::Program<'db>))] -#[visit(drive(crate::cst::ProgramChildren<'db>))] -#[visit(drive(crate::cst::PropertyIdentifier<'db>))] -#[visit(drive(crate::cst::PropertySignature<'db>))] -#[visit(drive(crate::cst::PropertySignatureChildren<'db>))] -#[visit(drive(crate::cst::PropertySignatureName<'db>))] -#[visit(drive(crate::cst::PublicFieldDefinition<'db>))] -#[visit(drive(crate::cst::PublicFieldDefinitionChildren<'db>))] -#[visit(drive(crate::cst::PublicFieldDefinitionName<'db>))] -#[visit(drive(crate::cst::ReadonlyType<'db>))] -#[visit(drive(crate::cst::ReadonlyTypeChildren<'db>))] -#[visit(drive(crate::cst::Regex<'db>))] -#[visit(drive(crate::cst::RegexChildren<'db>))] -#[visit(drive(crate::cst::RegexFlags<'db>))] -#[visit(drive(crate::cst::RegexPattern<'db>))] -#[visit(drive(crate::cst::RequiredParameter<'db>))] -#[visit(drive(crate::cst::RequiredParameterChildren<'db>))] -#[visit(drive(crate::cst::RequiredParameterName<'db>))] -#[visit(drive(crate::cst::RequiredParameterPattern<'db>))] -#[visit(drive(crate::cst::RestPattern<'db>))] -#[visit(drive(crate::cst::RestPatternChildren<'db>))] -#[visit(drive(crate::cst::RestType<'db>))] -#[visit(drive(crate::cst::RestTypeChildren<'db>))] -#[visit(drive(crate::cst::ReturnStatement<'db>))] -#[visit(drive(crate::cst::ReturnStatementChildren<'db>))] -#[visit(drive(crate::cst::SatisfiesExpression<'db>))] -#[visit(drive(crate::cst::SatisfiesExpressionChildren<'db>))] -#[visit(drive(crate::cst::SequenceExpression<'db>))] -#[visit(drive(crate::cst::SequenceExpressionChildren<'db>))] -#[visit(drive(crate::cst::ShorthandPropertyIdentifier<'db>))] -#[visit(drive(crate::cst::ShorthandPropertyIdentifierPattern<'db>))] -#[visit(drive(crate::cst::SpreadElement<'db>))] -#[visit(drive(crate::cst::SpreadElementChildren<'db>))] -#[visit(drive(crate::cst::Statement<'db>))] -#[visit(drive(crate::cst::StatementBlock<'db>))] -#[visit(drive(crate::cst::StatementBlockChildren<'db>))] -#[visit(drive(crate::cst::StatementIdentifier<'db>))] -#[visit(drive(crate::cst::String<'db>))] -#[visit(drive(crate::cst::StringChildren<'db>))] -#[visit(drive(crate::cst::StringFragment<'db>))] -#[visit(drive(crate::cst::SubscriptExpression<'db>))] -#[visit(drive(crate::cst::SubscriptExpressionChildren<'db>))] -#[visit(drive(crate::cst::SubscriptExpressionIndex<'db>))] -#[visit(drive(crate::cst::Super<'db>))] -#[visit(drive(crate::cst::SwitchBody<'db>))] -#[visit(drive(crate::cst::SwitchBodyChildren<'db>))] -#[visit(drive(crate::cst::SwitchCase<'db>))] -#[visit(drive(crate::cst::SwitchCaseChildren<'db>))] -#[visit(drive(crate::cst::SwitchCaseValue<'db>))] -#[visit(drive(crate::cst::SwitchDefault<'db>))] -#[visit(drive(crate::cst::SwitchDefaultChildren<'db>))] -#[visit(drive(crate::cst::SwitchStatement<'db>))] -#[visit(drive(crate::cst::SwitchStatementChildren<'db>))] -#[visit(drive(crate::cst::TemplateLiteralType<'db>))] -#[visit(drive(crate::cst::TemplateLiteralTypeChildren<'db>))] -#[visit(drive(crate::cst::TemplateString<'db>))] -#[visit(drive(crate::cst::TemplateStringChildren<'db>))] -#[visit(drive(crate::cst::TemplateSubstitution<'db>))] -#[visit(drive(crate::cst::TemplateSubstitutionChildren<'db>))] -#[visit(drive(crate::cst::TemplateType<'db>))] -#[visit(drive(crate::cst::TemplateTypeChildren<'db>))] -#[visit(drive(crate::cst::TernaryExpression<'db>))] -#[visit(drive(crate::cst::TernaryExpressionChildren<'db>))] -#[visit(drive(crate::cst::This<'db>))] -#[visit(drive(crate::cst::ThisType<'db>))] -#[visit(drive(crate::cst::ThrowStatement<'db>))] -#[visit(drive(crate::cst::ThrowStatementChildren<'db>))] -#[visit(drive(crate::cst::True<'db>))] -#[visit(drive(crate::cst::TryStatement<'db>))] -#[visit(drive(crate::cst::TryStatementChildren<'db>))] -#[visit(drive(crate::cst::TupleType<'db>))] -#[visit(drive(crate::cst::TupleTypeChildren<'db>))] -#[visit(drive(crate::cst::Type<'db>))] -#[visit(drive(crate::cst::TypeAliasDeclaration<'db>))] -#[visit(drive(crate::cst::TypeAliasDeclarationChildren<'db>))] -#[visit(drive(crate::cst::TypeAnnotation<'db>))] -#[visit(drive(crate::cst::TypeAnnotationChildren<'db>))] -#[visit(drive(crate::cst::TypeArguments<'db>))] -#[visit(drive(crate::cst::TypeArgumentsChildren<'db>))] -#[visit(drive(crate::cst::TypeAssertion<'db>))] -#[visit(drive(crate::cst::TypeAssertionChildren<'db>))] -#[visit(drive(crate::cst::TypeIdentifier<'db>))] -#[visit(drive(crate::cst::TypeParameter<'db>))] -#[visit(drive(crate::cst::TypeParameterChildren<'db>))] -#[visit(drive(crate::cst::TypeParameters<'db>))] -#[visit(drive(crate::cst::TypeParametersChildren<'db>))] -#[visit(drive(crate::cst::TypePredicate<'db>))] -#[visit(drive(crate::cst::TypePredicateAnnotation<'db>))] -#[visit(drive(crate::cst::TypePredicateAnnotationChildren<'db>))] -#[visit(drive(crate::cst::TypePredicateChildren<'db>))] -#[visit(drive(crate::cst::TypePredicateName<'db>))] -#[visit(drive(crate::cst::TypeQuery<'db>))] -#[visit(drive(crate::cst::TypeQueryChildren<'db>))] -#[visit(drive(crate::cst::UnaryExpression<'db>))] -#[visit(drive(crate::cst::UnaryExpressionArgument<'db>))] -#[visit(drive(crate::cst::UnaryExpressionChildren<'db>))] -#[visit(drive(crate::cst::UnaryExpressionOperator<'db>))] -#[visit(drive(crate::cst::Undefined<'db>))] -#[visit(drive(crate::cst::UnionType<'db>))] -#[visit(drive(crate::cst::UnionTypeChildren<'db>))] -#[visit(drive(crate::cst::UpdateExpression<'db>))] -#[visit(drive(crate::cst::UpdateExpressionChildren<'db>))] -#[visit(drive(crate::cst::UpdateExpressionOperator<'db>))] -#[visit(drive(crate::cst::VariableDeclaration<'db>))] -#[visit(drive(crate::cst::VariableDeclarationChildren<'db>))] -#[visit(drive(crate::cst::VariableDeclarator<'db>))] -#[visit(drive(crate::cst::VariableDeclaratorChildren<'db>))] -#[visit(drive(crate::cst::VariableDeclaratorName<'db>))] -#[visit(drive(crate::cst::WhileStatement<'db>))] -#[visit(drive(crate::cst::WhileStatementChildren<'db>))] -#[visit(drive(crate::cst::WithStatement<'db>))] -#[visit(drive(crate::cst::WithStatementChildren<'db>))] -#[visit(drive(crate::cst::YieldExpression<'db>))] -#[visit(drive(crate::cst::YieldExpressionChildren<'db>))] -#[visit(drive(forBox))] -#[visit(drive(forVec))] -#[visit(drive(forOption))] -#[visit( - enter(AbstractClassDeclaration:crate::cst::AbstractClassDeclaration<'db>), - enter(AbstractMethodSignature:crate::cst::AbstractMethodSignature<'db>), - enter(FunctionSignature:crate::cst::FunctionSignature<'db>), - enter(InterfaceDeclaration:crate::cst::InterfaceDeclaration<'db>), - enter(Module:crate::cst::Module<'db>) -)] +#[salsa::tracked] pub struct Definitions<'db> { - pub classes: BTreeMap>>, - pub functions: BTreeMap>>, - pub interfaces: BTreeMap>>, - pub methods: BTreeMap>>, - pub modules: BTreeMap>>, - phantom: std::marker::PhantomData<&'db ()>, + #[return_ref] + pub _classes: BTreeMap>, + #[return_ref] + pub _functions: BTreeMap>, + #[return_ref] + pub _interfaces: BTreeMap>, + #[return_ref] + pub _methods: BTreeMap>, + #[return_ref] + pub _modules: BTreeMap>, } impl<'db> Definitions<'db> { - fn enter_AbstractClassDeclaration( - &mut self, - node: &crate::cst::AbstractClassDeclaration<'db>, - ) { - ///Code for query: (abstract_class_declaration name: (type_identifier) @name) @definition.class - let name = &*node.name; - self.classes.entry(name.source()).or_insert(Vec::new()).push(node.clone()); + pub fn visit( + db: &'db dyn salsa::Database, + root: &'db crate::cst::Parsed<'db>, + ) -> Self { + let mut classes: BTreeMap> = BTreeMap::new(); + let mut functions: BTreeMap> = BTreeMap::new(); + let mut interfaces: BTreeMap> = BTreeMap::new(); + let mut methods: BTreeMap> = BTreeMap::new(); + let mut modules: BTreeMap> = BTreeMap::new(); + let tree = root.tree(db); + for (node, id) in tree.descendants(&root.program(db)) { + match node { + crate::cst::NodeTypes::AbstractClassDeclaration(node) => { + ///Code for query: (abstract_class_declaration name: (type_identifier) @name) @definition.class + let name = node.name(tree); + classes.entry(name.source()).or_default().push(id); + } + crate::cst::NodeTypes::AbstractMethodSignature(node) => { + ///Code for query: (abstract_method_signature name: (property_identifier) @name) @definition.method + let name = node.name(tree); + methods.entry(name.source()).or_default().push(id); + } + crate::cst::NodeTypes::FunctionSignature(node) => { + ///Code for query: (function_signature name: (identifier) @name) @definition.function + let name = node.name(tree); + functions.entry(name.source()).or_default().push(id); + } + crate::cst::NodeTypes::InterfaceDeclaration(node) => { + ///Code for query: (interface_declaration name: (type_identifier) @name) @definition.interface + let name = node.name(tree); + interfaces.entry(name.source()).or_default().push(id); + } + crate::cst::NodeTypes::Module(node) => { + ///Code for query: (module name: (identifier) @name) @definition.module + let name = node.name(tree); + modules.entry(name.source()).or_default().push(id); + } + _ => {} + } + } + Self::new(db, classes, functions, interfaces, methods, modules) } - fn enter_AbstractMethodSignature( - &mut self, - node: &crate::cst::AbstractMethodSignature<'db>, - ) { - ///Code for query: (abstract_method_signature name: (property_identifier) @name) @definition.method - let name = &*node.name; - self.methods.entry(name.source()).or_insert(Vec::new()).push(node.clone()); + pub fn default(db: &'db dyn salsa::Database) -> Self { + let mut classes: BTreeMap> = BTreeMap::new(); + let mut functions: BTreeMap> = BTreeMap::new(); + let mut interfaces: BTreeMap> = BTreeMap::new(); + let mut methods: BTreeMap> = BTreeMap::new(); + let mut modules: BTreeMap> = BTreeMap::new(); + Self::new(db, classes, functions, interfaces, methods, modules) } - fn enter_FunctionSignature(&mut self, node: &crate::cst::FunctionSignature<'db>) { - ///Code for query: (function_signature name: (identifier) @name) @definition.function - let name = &*node.name; - self.functions.entry(name.source()).or_insert(Vec::new()).push(node.clone()); + pub fn classes( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._classes(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() } - fn enter_InterfaceDeclaration( - &mut self, - node: &crate::cst::InterfaceDeclaration<'db>, - ) { - ///Code for query: (interface_declaration name: (type_identifier) @name) @definition.interface - let name = &*node.name; - self.interfaces.entry(name.source()).or_insert(Vec::new()).push(node.clone()); + pub fn functions( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._functions(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() } - fn enter_Module(&mut self, node: &crate::cst::Module<'db>) { - ///Code for query: (module name: (identifier) @name) @definition.module - let name = &*node.name; - self.modules.entry(name.source()).or_insert(Vec::new()).push(node.clone()); + pub fn interfaces( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._interfaces(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() + } + pub fn methods( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._methods(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() + } + pub fn modules( + &self, + db: &'db dyn salsa::Database, + tree: &'db codegen_sdk_common::tree::Tree>, + ) -> BTreeMap>> { + self._modules(db) + .iter() + .map(|(k, v)| ( + k.clone(), + v + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect(), + )) + .collect() } } diff --git a/codegen-sdk-ast-generator/src/visitor.rs b/codegen-sdk-ast-generator/src/visitor.rs index a0baeff0..7c3826a1 100644 --- a/codegen-sdk-ast-generator/src/visitor.rs +++ b/codegen-sdk-ast-generator/src/visitor.rs @@ -1,11 +1,10 @@ use std::collections::{BTreeMap, BTreeSet}; -use codegen_sdk_common::{CSTNode, HasChildren, Language}; -use codegen_sdk_ts_query::cst as ts_query; +use codegen_sdk_common::Language; use convert_case::{Case, Casing}; -use log::info; -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; +use syn::parse_quote_spanned; use super::query::Query; use crate::query::HasQuery; @@ -36,63 +35,71 @@ pub fn generate_visitor<'db>( .push(query); } } - let mut methods = Vec::new(); + let mut methods: Vec = Vec::new(); for (variant, queries) in enter_methods { let mut matchers = TokenStream::new(); - let enter = format_ident!("enter_{}", variant); let struct_name = format_ident!("{}", variant); for query in queries { matchers.extend_one(query.matcher(&variant)); - let node = query.node(); - for child in node.children() { - info!("child kind:{} source:{}", child.kind(), child.source()); - if let ts_query::NamedNodeChildren::FieldDefinition(field_definition) = child { - let field_name = &field_definition.name; - let source = field_definition.source(); - let children = &field_definition.children(); - info!("source: {:?}", source); - info!("field_name: {:?}", field_name); - info!("children: {:?}", children); - } - } } - methods.push(quote! { - fn #enter(&mut self, node: &crate::cst::#struct_name<'db>) { + let span = Span::mixed_site(); + methods.push(parse_quote_spanned! { span => + crate::cst::NodeTypes::#struct_name(node) => { #matchers } }); } - let visitor = if variants.len() > 0 { - let first_query = raw_queries.values().flatten().next().unwrap(); - let state = first_query.state.clone(); - let mut nodes = BTreeSet::new(); - nodes.extend(state.get_node_struct_names()); - nodes.extend(state.get_subenum_struct_names()); - nodes = nodes.difference(&variants).cloned().collect(); - quote! { - #(#[visit(drive(&crate::cst::#nodes<'db>))])* - #(#[visit(drive(&crate::cst::#variants<'db>))])* - #(#[visit(drive(crate::cst::#nodes<'db>))])* - #[visit(drive(for Box))] - #[visit(drive(for Vec))] - #[visit(drive(for Option))] - #[visit( - #(enter(#variants:crate::cst::#variants<'db>)),* - )] - } - } else { - quote! {} + let maps = quote! { + #( + let mut #names: BTreeMap> = BTreeMap::new(); + )* + }; + let constructor = quote! { + Self::new(db, #(#names),*) + }; let name = format_ident!("{}s", name.to_case(Case::Pascal)); + let output_constructor = quote! { + pub fn visit(db: &'db dyn salsa::Database, root: &'db crate::cst::Parsed<'db>) -> Self { + #maps + let tree = root.tree(db); + for (node, id) in tree.descendants(&root.program(db)) { + match node { + #(#methods,)* + _ => {} + } + } + #constructor + } + pub fn default(db: &'db dyn salsa::Database) -> Self { + #maps + #constructor + } + }; + let underscored_names = names + .iter() + .map(|name| format_ident!("_{}", name)) + .collect::>(); quote! { - #[derive(Visitor, Visit, Debug, Clone, Eq, PartialEq, salsa::Update, Hash, Default)] - #visitor + // Three lifetimes: + // db: the lifetime of the database + // db1: the lifetime of the visitor executing per-node + // db2: the lifetime of the references held by the visitor + #[salsa::tracked] pub struct #name<'db> { - #(pub #names: BTreeMap>>,)* - phantom: std::marker::PhantomData<&'db ()>, + #( + #[return_ref] + pub #underscored_names: BTreeMap>, + )* } impl<'db> #name<'db> { - #(#methods)* + #output_constructor + #( + pub fn #names(&self, db: &'db dyn salsa::Database, tree: &'db codegen_sdk_common::tree::Tree>) -> BTreeMap>> { + self.#underscored_names(db).iter().map(|(k, v)| + (k.clone(), v.iter().map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()).collect())).collect() + } + )* } } } diff --git a/codegen-sdk-ast/src/lib.rs b/codegen-sdk-ast/src/lib.rs index f0fd4679..cb9958ff 100644 --- a/codegen-sdk-ast/src/lib.rs +++ b/codegen-sdk-ast/src/lib.rs @@ -15,20 +15,10 @@ impl Named for T { #[delegatable_trait] pub trait Definitions<'db> { type Definitions; - fn definitions(self, db: &'db dyn salsa::Database) -> Self::Definitions; + fn definitions(self, db: &'db dyn salsa::Database) -> &'db Self::Definitions; } #[delegatable_trait] pub trait References<'db> { type References; - fn references(self, db: &'db dyn salsa::Database) -> Self::References; -} -#[delegatable_trait] -pub trait FileExt<'db>: References<'db> + Definitions<'db> + Clone { - fn precompute(self, db: &'db dyn salsa::Database) - where - Self: Sized, - { - self.clone().definitions(db); - self.references(db); - } + fn references(self, db: &'db dyn salsa::Database) -> &'db Self::References; } diff --git a/codegen-sdk-common/Cargo.toml b/codegen-sdk-common/Cargo.toml index b7cad729..a1b418b4 100644 --- a/codegen-sdk-common/Cargo.toml +++ b/codegen-sdk-common/Cargo.toml @@ -18,7 +18,7 @@ tree-sitter-yaml = { workspace = true, optional = true } tree-sitter-toml-ng = { workspace = true, optional = true } tree-sitter-md = { workspace = true, optional = true } lazy_static = "1.5.0" -thiserror = "2.0.11" +thiserror = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } anyhow = { workspace = true } @@ -28,6 +28,8 @@ phf = { version = "0.11.3", features = ["macros"] } rkyv = { workspace = true } xdg = "2.5.2" base64 = "0.22.1" +proc-macro2 = { workspace = true } +quote = { workspace = true } buildid = "1.0.3" sha2 = "0.10.8" zstd = { version = "0.13.2", features = ["zstdmt"], optional = true } @@ -36,6 +38,7 @@ mockall = { workspace = true } syn = { workspace = true } prettyplease = { workspace = true } salsa = { workspace = true } +indextree = { workspace = true } [dev-dependencies] test-log = { workspace = true } [features] diff --git a/codegen-sdk-common/src/lib.rs b/codegen-sdk-common/src/lib.rs index 55eabdb6..67d9a919 100644 --- a/codegen-sdk-common/src/lib.rs +++ b/codegen-sdk-common/src/lib.rs @@ -17,5 +17,5 @@ pub mod naming; #[cfg(feature = "serialization")] pub mod serialize; pub mod tree; -pub use tree::{Point, Range}; +pub use tree::{CSTNodeId, FileNodeId, Point, Range, Tree, TreeNode}; pub mod generator; diff --git a/codegen-sdk-common/src/naming.rs b/codegen-sdk-common/src/naming.rs index 00d0d476..c57d5a8a 100644 --- a/codegen-sdk-common/src/naming.rs +++ b/codegen-sdk-common/src/naming.rs @@ -38,6 +38,13 @@ static MAPPINGS: phf::Map = phf_map! { ';' => "Semicolon", '\0' => "Null", }; +pub fn field_name_getter(field_name: &str) -> String { + if field_name == "source" { + return "source_node".to_string(); + } + field_name.to_string() +} + pub fn normalize_field_name(field_name: &str) -> String { if field_name == "type" { return "r#type".to_string(); diff --git a/codegen-sdk-common/src/parser.rs b/codegen-sdk-common/src/parser.rs index 2219e7d0..17db4338 100644 --- a/codegen-sdk-common/src/parser.rs +++ b/codegen-sdk-common/src/parser.rs @@ -1,3 +1,5 @@ +use proc_macro2::Ident; +use quote::format_ident; use serde::{Deserialize, Serialize}; use crate::naming::normalize_type_name; @@ -41,6 +43,9 @@ impl TypeDefinition { pub fn normalize(&self) -> String { normalize_type_name(&self.type_name, self.named) } + pub fn ident(&self) -> Ident { + format_ident!("{}", self.normalize()) + } } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] pub struct Children { diff --git a/codegen-sdk-common/src/traits.rs b/codegen-sdk-common/src/traits.rs index 5feca529..e3f87549 100644 --- a/codegen-sdk-common/src/traits.rs +++ b/codegen-sdk-common/src/traits.rs @@ -1,19 +1,39 @@ -use std::{fmt::Debug, sync::Arc}; +use std::fmt::Debug; use ambassador::delegatable_trait; use bytes::Bytes; +use indextree::NodeId; use tree_sitter::{self}; -use crate::{Point, errors::ParseError, tree::Range}; -pub trait FromNode<'db>: Sized { +use crate::{ + Point, Tree, + errors::ParseError, + tree::{CSTNodeId, FileNodeId, ParseContext, TreeNode}, +}; +pub trait FromNode<'db, Types: TreeNode>: Sized { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, Types>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result; + ) -> Result<(Self, Vec), ParseError>; + fn orphaned( + context: &mut ParseContext<'db, Types>, + node: tree_sitter::Node, + ) -> Result + where + Self: Into, + Types: CSTNode<'db>, + { + let (raw, mut children) = Self::from_node(context, node)?; + children.sort_by_key(|id| context.tree.get(id).unwrap().start_byte()); + let id = context.tree.insert_with_children(raw.into(), children); + Ok(id) + } } #[delegatable_trait] -pub trait CSTNode<'db> { +pub trait CSTNode<'db> +where + Self: 'db, +{ /// Returns the byte offset where the node starts fn start_byte(&self) -> usize; @@ -42,7 +62,7 @@ pub trait CSTNode<'db> { fn kind_id(&self) -> u16; /// Returns the node's type as a string - fn kind(&self) -> &str; + fn kind_name(&self) -> &str; /// Returns true if this node is named, false if it is anonymous fn is_named(&self) -> bool; @@ -66,65 +86,74 @@ pub trait CSTNode<'db> { fn is_extra(&self) -> bool { unimplemented!("is_extra not implemented") } - fn id(&self) -> usize; -} -pub trait CSTNodeExt<'db>: CSTNode<'db> { - /// Get the next sibling of this node in its parent - fn next_sibling + Clone, Parent: HasChildren<'db, Child = Child>>( - &self, - parent: &Parent, - ) -> Option { - let mut iter = parent.children().into_iter(); - while let Some(child) = iter.next() { - if child.id() == self.id() { - return iter.next(); - } - } - None - } - fn next_named_sibling + Clone, Parent: HasChildren<'db, Child = Child>>( - &self, - parent: &Parent, - ) -> Option { - let mut iter = parent.named_children().into_iter(); - while let Some(child) = iter.next() { - if child.id() == self.id() { - return iter.next(); - } - } - None - } - fn prev_sibling + Clone, Parent: HasChildren<'db, Child = Child>>( - &self, - parent: &Parent, - ) -> Option { - let mut prev = None; - for child in parent.children() { - if child.id() == self.id() { - return prev; - } - prev = Some(child); - } - None - } - fn prev_named_sibling + Clone, Parent: HasChildren<'db, Child = Child>>( - &self, - parent: &Parent, - ) -> Option { - let mut prev = None; - for child in parent.named_children() { - if child.id() == self.id() { - return prev; - } - prev = Some(child); - } - None - } - /// Returns the range of positions that this node spans - fn range(&self, db: &'db dyn salsa::Database) -> Range<'db> { - Range::from_points(db, self.start_position(), self.end_position()) - } + fn id(&self) -> CSTNodeId<'db>; + fn file_id(&self) -> FileNodeId<'db>; } + +// pub trait CSTNodeExt<'db>: CSTNode<'db> { +// /// Get the next sibling of this node in its parent +// fn next_sibling + Clone, Parent: HasChildren<'db, Child<'db> = Child>>( +// &self, +// parent: &'db Parent, +// tree: &'db dyn Tree, +// ) -> Option { +// let mut iter = parent.children().into_iter(); +// while let Some(child) = iter.next() { +// if child.id() == self.id() { +// return iter.next(); +// } +// } +// None +// } +// fn next_named_sibling< +// Child: CSTNode<'db> + Clone, +// Parent: HasChildren<'db, Child<'db> = Child>, +// >( +// &self, +// parent: &'db Parent, +// ) -> Option { +// let mut iter = parent.named_children().into_iter(); +// while let Some(child) = iter.next() { +// if child.id() == self.id() { +// return iter.next(); +// } +// } +// None +// } +// fn prev_sibling + Clone, Parent: HasChildren<'db, Child<'db> = Child>>( +// &self, +// parent: &'db Parent, +// ) -> Option { +// let mut prev = None; +// for child in parent.children() { +// if child.id() == self.id() { +// return prev; +// } +// prev = Some(child); +// } +// None +// } +// fn prev_named_sibling< +// Child: CSTNode<'db> + Clone, +// Parent: HasChildren<'db, Child<'db> = Child>, +// >( +// &self, +// parent: &'db Parent, +// ) -> Option { +// let mut prev = None; +// for child in parent.named_children() { +// if child.id() == self.id() { +// return prev; +// } +// prev = Some(child); +// } +// None +// } +// /// Returns the range of positions that this node spans +// fn range(&self, db: &'db dyn salsa::Database) -> Range<'db> { +// Range::from_points(db, self.start_position(), self.end_position()) +// } +// } // pub trait HasNode<'db>: Send + Debug + Clone { // type Node: CSTNode<'db>; // fn node(&self) -> &Self::Node; @@ -189,33 +218,62 @@ pub trait CSTNodeExt<'db>: CSTNode<'db> { // self.node().child_count() // } // } -pub trait HasChildren<'db> { - type Child: Send + Debug + Clone + CSTNode<'db>; +pub trait HasChildren<'db, Types: TreeNode> { + type Child<'db2>: Send + Debug + where + Self: 'db2, + Types: 'db2, + 'db: 'db2; /// Returns the first child with the given field name - fn child_by_field_id(&self, field_id: u16) -> Option { - self.children_by_field_id(field_id) + fn child_by_field_id<'db1>( + &'db1 self, + context: &'db1 Tree, + field_id: u16, + ) -> Option> + where + Self::Child<'db1>: Clone, + { + self.children_by_field_id(context, field_id) .first() .map(|child| child.clone()) } /// Returns all children with the given field name - fn children_by_field_id(&self, _field_id: u16) -> Vec; + fn children_by_field_id<'db1>( + &'db1 self, + context: &'db1 Tree, + field_id: u16, + ) -> Vec>; /// Returns the first child with the given field name - fn child_by_field_name(&self, field_name: &str) -> Option { - self.children_by_field_name(field_name) + fn child_by_field_name<'db1>( + &'db1 self, + context: &'db1 Tree, + field_name: &str, + ) -> Option> + where + Self::Child<'db1>: Clone, + { + self.children_by_field_name(context, field_name) .first() .map(|child| child.clone()) } /// Returns all children with the given field name - fn children_by_field_name(&self, field_name: &str) -> Vec; + fn children_by_field_name<'db1>( + &'db1 self, + context: &'db1 Tree, + field_name: &str, + ) -> Vec>; /// Returns all children of the node - fn children(&self) -> Vec; + fn children<'db1>(&'db1 self, context: &'db1 Tree) -> Vec>; /// Returns all named children of the node - fn named_children(&self) -> Vec { - self.children() + fn named_children<'db1>(&'db1 self, context: &'db1 Tree) -> Vec> + where + Self::Child<'db1>: CSTNode<'db1>, + { + self.children(context) .into_iter() .filter(|child| child.is_named()) .collect() @@ -230,31 +288,63 @@ pub trait HasChildren<'db> { // } /// Returns the first child of the node - fn first_child(&self) -> Option { - self.children().into_iter().next() + fn first_child<'db1>(&'db1 self, context: &'db1 Tree) -> Option> { + self.children(context).into_iter().next() } /// Returns the last child of the node - fn last_child(&self) -> Option { - self.children().into_iter().last() + fn last_child<'db1>(&'db1 self, context: &'db1 Tree) -> Option> { + self.children(context).into_iter().last() } /// Returns the number of children of this node - fn child_count(&self) -> usize { - self.children().len() + fn child_count(&'db self, context: &'db Tree) -> usize { + self.children(context).len() } - fn children_by_field_types(&self, field_types: &[&str]) -> Vec { - self.children() + fn children_by_field_types<'db1>( + &'db1 self, + context: &'db1 Tree, + field_types: &[&str], + ) -> Vec> + where + Self::Child<'db1>: CSTNode<'db1>, + { + self.children(context) .into_iter() - .filter(|child| field_types.contains(&child.kind())) + .filter(|child| field_types.contains(&child.kind_name())) .collect() } - fn children_by_field_type(&self, field_type: &str) -> Vec { - self.children_by_field_types(&[field_type]) + fn children_by_field_type<'db1>( + &'db1 self, + context: &'db1 Tree, + field_type: &str, + ) -> Vec> + where + Self::Child<'db1>: CSTNode<'db1>, + { + self.children_by_field_types(context, &[field_type]) } - fn child_by_field_type(&self, field_type: &str) -> Option { - self.children_by_field_type(field_type).into_iter().next() + fn child_by_field_type<'db1>( + &'db1 self, + context: &'db1 Tree, + field_type: &str, + ) -> Option> + where + Self::Child<'db1>: CSTNode<'db1>, + { + self.children_by_field_type(context, field_type) + .into_iter() + .next() } - fn child_by_field_types(&self, field_types: &[&str]) -> Option { - self.children_by_field_types(field_types).into_iter().next() + fn child_by_field_types<'db1>( + &'db1 self, + context: &'db1 Tree, + field_types: &[&str], + ) -> Option> + where + Self::Child<'db1>: CSTNode<'db1>, + { + self.children_by_field_types(context, field_types) + .into_iter() + .next() } } diff --git a/codegen-sdk-common/src/tree.rs b/codegen-sdk-common/src/tree.rs index 6a815a7d..5aea5125 100644 --- a/codegen-sdk-common/src/tree.rs +++ b/codegen-sdk-common/src/tree.rs @@ -1,6 +1,12 @@ // mod cursor; mod point; mod range; +mod tree; // pub use cursor::TreeCursor; pub use point::Point; pub use range::Range; +mod id; +pub use id::{CSTNodeId, FileNodeId}; +mod context; +pub use context::ParseContext; +pub use tree::{Tree, TreeNode}; diff --git a/codegen-sdk-common/src/tree/context.rs b/codegen-sdk-common/src/tree/context.rs new file mode 100644 index 00000000..1cf94dcc --- /dev/null +++ b/codegen-sdk-common/src/tree/context.rs @@ -0,0 +1,22 @@ +use std::{path::PathBuf, sync::Arc}; + +use bytes::Bytes; + +use crate::tree::{FileNodeId, Tree, TreeNode}; +pub struct ParseContext<'db, T: TreeNode> { + pub db: &'db dyn salsa::Database, + pub file_id: FileNodeId<'db>, + pub buffer: Arc, + pub tree: Tree, +} +impl<'db, T: TreeNode> ParseContext<'db, T> { + pub fn new(db: &'db dyn salsa::Database, path: PathBuf, content: Bytes) -> Self { + let file_id = FileNodeId::new(db, path); + Self { + db, + file_id, + buffer: Arc::new(content), + tree: Tree::default(), + } + } +} diff --git a/codegen-sdk-common/src/tree/id.rs b/codegen-sdk-common/src/tree/id.rs new file mode 100644 index 00000000..b665416a --- /dev/null +++ b/codegen-sdk-common/src/tree/id.rs @@ -0,0 +1,12 @@ +use std::path::PathBuf; + +#[salsa::interned] +pub struct FileNodeId<'db> { + file_path: PathBuf, +} +#[salsa::interned] +pub struct CSTNodeId<'db> { + file_id: FileNodeId<'db>, + node_id: usize, + // TODO: add a marker for tree-sitter generation +} diff --git a/codegen-sdk-common/src/tree/tree.rs b/codegen-sdk-common/src/tree/tree.rs new file mode 100644 index 00000000..ae884cd6 --- /dev/null +++ b/codegen-sdk-common/src/tree/tree.rs @@ -0,0 +1,50 @@ +use std::hash::Hash; + +use indextree::{Arena, NodeId}; +use salsa::Update; +pub trait TreeNode: Eq + PartialEq {} +#[derive(Debug, Eq, PartialEq)] +pub struct Tree { + ids: Arena, +} +impl Hash for Tree { + fn hash(&self, state: &mut H) { + self.ids.count().hash(state); + } +} +impl Default for Tree { + fn default() -> Self { + Self { ids: Arena::new() } + } +} +impl Tree { + pub fn insert(&mut self, value: T) -> NodeId { + self.ids.new_node(value) + } + pub fn insert_with_children(&mut self, value: T, children: Vec) -> NodeId { + let id = self.insert(value); + for child in children { + id.append(child, &mut self.ids); + } + id + } + pub fn get(&self, id: &NodeId) -> Option<&T> { + self.ids.get(*id).map(|node| node.get()) + } + pub fn descendants(&self, id: &NodeId) -> impl Iterator { + id.descendants(&self.ids) + .map(|id| (self.get(&id).unwrap(), id)) + } + pub fn children(&self, id: &NodeId) -> impl Iterator { + id.children(&self.ids) + .map(|id| (self.get(&id).unwrap(), id)) + } +} +unsafe impl Update for Tree +where + T: TreeNode + Update, +{ + unsafe fn maybe_update(_old_pointer: *mut Self, _new_set: Self) -> bool { + todo!("Tree is not updateable"); + } +} diff --git a/codegen-sdk-common/src/utils.rs b/codegen-sdk-common/src/utils.rs index 93f035c2..d6073f6a 100644 --- a/codegen-sdk-common/src/utils.rs +++ b/codegen-sdk-common/src/utils.rs @@ -1,41 +1,54 @@ -use std::{backtrace::Backtrace, sync::Arc}; +use std::backtrace::Backtrace; -use bytes::Bytes; +use indextree::NodeId; use tree_sitter::{self}; -use crate::{ParseError, traits::FromNode}; -pub fn named_children_without_field_names<'db, T: FromNode<'db>>( - db: &'db dyn salsa::Database, +use crate::{ + ParseError, + traits::{CSTNode, FromNode}, + tree::{ParseContext, TreeNode}, +}; +pub fn named_children_without_field_names< + 'db, + Types: From + TreeNode + CSTNode<'db>, + T: FromNode<'db, Types>, +>( + context: &mut ParseContext<'db, Types>, node: tree_sitter::Node, - buffer: &Arc, -) -> Result, ParseError> { +) -> Result, ParseError> { let mut children = Vec::new(); for (index, child) in node.named_children(&mut node.walk()).enumerate() { if node.field_name_for_named_child(index as u32).is_none() { - children.push(T::from_node(db, child, buffer)?); + children.push(T::orphaned(context, child)?); } } Ok(children) } -pub fn get_optional_child_by_field_name<'db, T: FromNode<'db>>( - db: &'db dyn salsa::Database, +pub fn get_optional_child_by_field_name< + 'db, + Types: From + TreeNode + CSTNode<'db>, + T: FromNode<'db, Types>, +>( + context: &mut ParseContext<'db, Types>, node: &tree_sitter::Node, field_name: &str, - buffer: &Arc, -) -> Result, ParseError> { +) -> Result, ParseError> { if let Some(child) = node.child_by_field_name(field_name) { - return Ok(Some(T::from_node(db, child, buffer)?)); + return Ok(Some(T::orphaned(context, child)?)); } Ok(None) } -pub fn get_child_by_field_name<'db, T: FromNode<'db>>( - db: &'db dyn salsa::Database, +pub fn get_child_by_field_name< + 'db, + Types: From + TreeNode + CSTNode<'db>, + T: FromNode<'db, Types>, +>( + context: &mut ParseContext<'db, Types>, node: &tree_sitter::Node, field_name: &str, - buffer: &Arc, -) -> Result { - if let Some(child) = get_optional_child_by_field_name(db, node, field_name, buffer)? { +) -> Result { + if let Some(child) = get_optional_child_by_field_name(context, node, field_name)? { return Ok(child); } Err(ParseError::MissingNode { @@ -45,15 +58,18 @@ pub fn get_child_by_field_name<'db, T: FromNode<'db>>( }) } -pub fn get_multiple_children_by_field_name<'db, T: FromNode<'db>>( - db: &'db dyn salsa::Database, +pub fn get_multiple_children_by_field_name< + 'db, + Types: From + TreeNode + CSTNode<'db>, + T: FromNode<'db, Types>, +>( + context: &mut ParseContext<'db, Types>, node: &tree_sitter::Node, field_name: &str, - buffer: &Arc, -) -> Result, ParseError> { +) -> Result, ParseError> { let mut children = Vec::new(); for child in node.children_by_field_name(field_name, &mut node.walk()) { - children.push(T::from_node(db, child, buffer)?); + children.push(T::orphaned(context, child)?); } Ok(children) } diff --git a/codegen-sdk-cst-generator/src/generator.rs b/codegen-sdk-cst-generator/src/generator.rs index 76771554..08276586 100644 --- a/codegen-sdk-cst-generator/src/generator.rs +++ b/codegen-sdk-cst-generator/src/generator.rs @@ -25,9 +25,12 @@ fn get_imports(config: &Config) -> TokenStream { use subenum::subenum; use std::backtrace::Backtrace; use bytes::Bytes; - use derive_generic_visitor::Drive; use ambassador::Delegate; + use derive_more::Debug; + use ambassador::delegate_to_methods; use codegen_sdk_cst::CSTLanguage; + use crate::cst::tree::ParseContext; + use std::path::PathBuf; }; if config.serialize { imports.extend_one(quote! { @@ -42,13 +45,18 @@ fn get_parser(language: &Language) -> TokenStream { let language_struct_name = format_ident!("{}", language.struct_name()); let root_node = format_ident!("{}", language.root_node()); quote! { + impl<'db> TreeNode for NodeTypes<'db> {} #[salsa::tracked] pub struct Parsed<'db> { + #[id] + id: FileNodeId<'db>, #[tracked] #[return_ref] - pub program: Option<#program_id<'db>>, + #[no_clone] + pub tree: Tree>, + pub program: indextree::NodeId, } - pub fn parse_program_raw(db: &dyn salsa::Database, input: codegen_sdk_cst::Input) -> Option<#program_id<'_>> { + pub fn parse_program_raw<'db>(db: &'db dyn salsa::Database, input: codegen_sdk_cst::Input, path: PathBuf) -> Option> { let buffer = Bytes::from(input.content(db).as_bytes().to_vec()); let tree = codegen_sdk_common::language::#language_name::#language_struct_name.parse_tree_sitter(&input.content(db)); match tree { @@ -57,14 +65,19 @@ fn get_parser(language: &Language) -> TokenStream { ParseError::SyntaxError.report(db); None } else { - let buffer = Arc::new(buffer); - #program_id::from_node(db, tree.root_node(), &buffer) + let mut context = ParseContext::new(db, path, buffer); + let root_id = #program_id::orphaned(&mut context, tree.root_node()) .map_or_else(|e| { e.report(db); None }, |program| { Some(program) - }) + }); + if let Some(program) = root_id { + Some(Parsed::new(db, context.file_id, context.tree, program)) + } else { + None + } } } Err(e) => { @@ -73,19 +86,29 @@ fn get_parser(language: &Language) -> TokenStream { } } } - #[salsa::tracked] + #[salsa::tracked(return_ref)] pub fn parse_program(db: &dyn salsa::Database, input: codegen_sdk_cst::Input) -> Parsed<'_> { - Parsed::new(db, parse_program_raw(db, input)) + let raw = parse_program_raw(db, input, std::path::PathBuf::new()); + if let Some(parsed) = raw { + parsed + } else { + panic!("Failed to parse program"); + } } pub struct #language_struct_name; impl CSTLanguage for #language_struct_name { + type Types<'db> = NodeTypes<'db>; type Program<'db> = #root_node<'db>; fn language() -> &'static codegen_sdk_common::language::Language { &codegen_sdk_common::language::#language_name::#language_struct_name } - fn parse<'db>(db: &'db dyn salsa::Database, content: std::string::String) -> &'db Option> { + fn parse<'db>(db: &'db dyn salsa::Database, content: std::string::String) -> Option<(&'db Self::Program<'db>, &'db Tree>)> { let input = codegen_sdk_cst::Input::new(db, content); - return parse_program(db, input).program(db); + let parsed = parse_program(db, input); + let program = parsed.program(db); + let tree = parsed.tree(db); + let program = tree.get(&program).unwrap().as_ref(); + Some((program.try_into().unwrap(), tree)) } } } @@ -93,12 +116,14 @@ fn get_parser(language: &Language) -> TokenStream { pub fn generate_cst(language: &Language, config: Config) -> anyhow::Result { let imports: TokenStream = get_imports(&config); let state = State::new(language, config); - let enums = state.get_enum(); + let enums = state.get_enum(false); + let enums_ref = state.get_enum(true); let structs = state.get_structs(); let parser = get_parser(language); let result: syn::File = parse_quote! { #imports #enums + #enums_ref #structs #parser }; diff --git a/codegen-sdk-cst-generator/src/generator/constants.rs b/codegen-sdk-cst-generator/src/generator/constants.rs index 1f77b4a2..c22b5ddd 100644 --- a/codegen-sdk-cst-generator/src/generator/constants.rs +++ b/codegen-sdk-cst-generator/src/generator/constants.rs @@ -1 +1,2 @@ pub const TYPE_NAME: &str = "NodeTypes"; +pub const TYPE_NAME_REF: &str = "NodeTypesRef"; diff --git a/codegen-sdk-cst-generator/src/generator/field.rs b/codegen-sdk-cst-generator/src/generator/field.rs index 388db95a..e36d365c 100644 --- a/codegen-sdk-cst-generator/src/generator/field.rs +++ b/codegen-sdk-cst-generator/src/generator/field.rs @@ -1,14 +1,16 @@ +use std::collections::HashSet; + #[double] use codegen_sdk_common::language::Language; use codegen_sdk_common::{ - naming::{normalize_field_name, normalize_type_name}, + naming::{field_name_getter, normalize_field_name, normalize_type_name}, parser::{FieldDefinition, TypeDefinition}, }; use mockall_double::double; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use syn::parse_quote; -use super::constants::TYPE_NAME; use crate::Config; #[derive(Debug)] @@ -56,47 +58,75 @@ impl<'a> Field<'a> { format!("{}{}", self.node_name, self.normalized_name()) } } + pub fn type_name_ref(&self, subenums: &HashSet<&String>) -> TokenStream { + let types = self.types(); + // We return a direct reference if the there is only one type and it is not a subenum + if types.len() == 1 { + let ident = format_ident!("{}", types[0].normalize()); + if subenums.contains(&types[0].type_name) { + let ident = format_ident!("{}Ref", ident); + quote! {#ident} + } else { + quote! { + &#ident + } + } + } else { + let ident = format_ident!("{}{}Ref", self.node_name, self.normalized_name()); + quote! { + #ident + } + } + } + pub fn get_constructor_field(&self) -> TokenStream { let field_name_ident = format_ident!("{}", self.name()); let original_name = &self.name; + let converted_type_name = format_ident!("{}", self.type_name()); if self.raw.multiple { quote! { - #field_name_ident: get_multiple_children_by_field_name(db, &node, #original_name, buffer)? + let #field_name_ident= get_multiple_children_by_field_name::, #converted_type_name<'db>>(context, &node, #original_name)?; + for child in #field_name_ident.iter().cloned() { + ids.push(child); + } } } else if !self.raw.required { quote! { - #field_name_ident: Box::new(get_optional_child_by_field_name(db, &node, #original_name, buffer)?) + let #field_name_ident = get_optional_child_by_field_name::, #converted_type_name<'db>>(context, &node, #original_name)?; + if let Some(child) = #field_name_ident.clone() { + ids.push(child); + } } } else { quote! { - #field_name_ident: Box::new(get_child_by_field_name(db,&node, #original_name, buffer)?) + let #field_name_ident = get_child_by_field_name::, #converted_type_name<'db>>(context, &node, #original_name)?; + ids.push(#field_name_ident.clone()); } } } pub fn get_convert_child(&self, convert_children: bool) -> TokenStream { let field_name_ident = format_ident!("{}", self.name()); - let types = format_ident!("{}", TYPE_NAME); if convert_children { if self.raw.multiple { quote! { - Self::Child::try_from(#types::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() } } else if !self.raw.required { quote! { - Self::Child::try_from(#types::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() } } else { quote! { - Self::Child::try_from(#types::from(self.#field_name_ident.as_ref().clone())).unwrap() + context.get(&self.#field_name_ident).unwrap().as_ref().try_into().unwrap() } } } else if self.raw.multiple || !self.raw.required { quote! { - child.clone() + child } } else { quote! { - self.#field_name_ident.as_ref().clone() + self.#field_name_ident.as_ref() } } } @@ -160,7 +190,6 @@ impl<'a> Field<'a> { } pub fn get_struct_field(&self) -> TokenStream { let field_name_ident = format_ident!("{}", self.name()); - let converted_type_name = format_ident!("{}", self.type_name()); let bounds = if self.config.serialize { quote! { #[rkyv(omit_bounds)] @@ -171,20 +200,49 @@ impl<'a> Field<'a> { if self.raw.multiple { quote! { #bounds - pub #field_name_ident: Vec<#converted_type_name<'db>> + pub #field_name_ident: Vec } } else if !self.raw.required { quote! { #bounds - pub #field_name_ident: Box>> + pub #field_name_ident: Option } } else { quote! { #bounds - pub #field_name_ident: Box<#converted_type_name<'db>> + pub #field_name_ident: indextree::NodeId } } } + pub fn get_field_getter(&self, subenums: &HashSet<&String>) -> syn::ImplItemFn { + let function_name = format_ident!("{}", field_name_getter(&self.name())); + let field_name_ident = format_ident!("{}", self.name()); + let converted_type_name = self.type_name_ref(subenums); + if self.raw.multiple { + parse_quote! { + pub fn #function_name(&self, tree: &'db Tree>) -> Vec<#converted_type_name<'db>> { + self.#field_name_ident.iter().map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()).collect() + } + } + } else if !self.raw.required { + parse_quote! { + pub fn #function_name(&self, tree: &'db Tree>) -> Option<#converted_type_name<'db>> { + if let Some(id) = self.#field_name_ident { + Some(tree.get(&id).unwrap().as_ref().try_into().unwrap()) + } else { + None + } + } + } + } else { + parse_quote! { + pub fn #function_name(&self, tree: &'db Tree>) -> #converted_type_name<'db> { + tree.get(&self.#field_name_ident).unwrap().as_ref().try_into().unwrap() + } + } + } + } + pub fn is_optional(&self) -> bool { !self.raw.required } @@ -366,7 +424,7 @@ mod tests { assert_eq!( field.get_children_field(true).to_string(), - quote!(children.push(Self::Child::try_from(NodeTypes::from(self.test_field.as_ref().clone())).unwrap());).to_string() + quote!(children.push(context.get(&self.test_field).unwrap().as_ref().try_into().unwrap());).to_string() ); // Test optional field @@ -382,7 +440,7 @@ mod tests { assert_eq!( optional_field.get_children_field(true).to_string(), quote!(if let Some(child) = self.test_field.as_ref() { - children.push(Self::Child::try_from(NodeTypes::from(child.clone())).unwrap()); + children.push(context.get(child).unwrap().as_ref().try_into().unwrap()); }) .to_string() ); @@ -399,7 +457,7 @@ mod tests { assert_eq!( multiple_field.get_children_field(true).to_string(), - quote!(children.extend(self.test_field.iter().map(|child| Self::Child::try_from(NodeTypes::from(child.clone())).unwrap()));).to_string() + quote!(children.extend(self.test_field.iter().map(|child| context.get(child).unwrap().as_ref().try_into().unwrap()));).to_string() ); } @@ -417,7 +475,7 @@ mod tests { assert_eq!( field.get_children_by_field_name_field(true).to_string(), - quote!("test_field" => vec![Self::Child::try_from(NodeTypes::from(self.test_field.as_ref().clone())).unwrap()]).to_string() + quote!("test_field" => vec![context.get(&self.test_field).unwrap().as_ref().try_into().unwrap()]).to_string() ); // Test optional field @@ -432,7 +490,7 @@ mod tests { assert_eq!( optional_field.get_children_by_field_name_field(true).to_string(), - quote!("test_field" => self.test_field.as_ref().iter().map(|child| Self::Child::try_from(NodeTypes::from(child.clone())).unwrap()).collect()).to_string() + quote!("test_field" => self.test_field.as_ref().iter().map(|child| context.get(child).unwrap().as_ref().try_into().unwrap()).collect()).to_string() ); // Test multiple field @@ -447,7 +505,7 @@ mod tests { assert_eq!( multiple_field.get_children_by_field_name_field(true).to_string(), - quote!("test_field" => self.test_field.iter().map(|child| Self::Child::try_from(NodeTypes::from(child.clone())).unwrap()).collect()).to_string() + quote!("test_field" => self.test_field.iter().map(|child| context.get(child).unwrap().as_ref().try_into().unwrap()).collect()).to_string() ); } } diff --git a/codegen-sdk-cst-generator/src/generator/node.rs b/codegen-sdk-cst-generator/src/generator/node.rs index 861aec3c..5e64a3a4 100644 --- a/codegen-sdk-cst-generator/src/generator/node.rs +++ b/codegen-sdk-cst-generator/src/generator/node.rs @@ -1,4 +1,7 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; #[double] use codegen_sdk_common::language::Language; @@ -70,22 +73,37 @@ impl<'a> Node<'a> { self.subenums.push(subenum); } } - pub fn get_enum_tokens(&self, subenum_name_map: &HashMap) -> TokenStream { + pub fn get_enum_tokens( + &self, + subenum_name_map: &HashMap, + is_ref: bool, + ) -> TokenStream { let name = format_ident!("{}", self.normalize_name()); + let value = if is_ref { + quote! { &'db1 #name } + } else { + quote! { #name } + }; let subenum_names = &self .subenums .iter() .map(|s| subenum_name_map.get(s).unwrap_or(&s)) - .map(|s| format_ident!("{}", s)) + .map(|s| { + if is_ref { + format_ident!("{}Ref", s) + } else { + format_ident!("{}", s) + } + }) .collect::>(); if subenum_names.is_empty() { quote! { - #name(#name<'db1>) + #name(#value<'db1>) } } else { quote! { #[subenum(#(#subenum_names), *)] - #name(#name<'db1>) + #name(#value<'db1>) } } } @@ -118,7 +136,6 @@ impl<'a> Node<'a> { } fn get_children_field(&self) -> TokenStream { if self.has_children() { - let children_type_name = format_ident!("{}", self.children_struct_name()); let bounds = if self.config.serialize { quote! { #[rkyv(omit_bounds)] @@ -128,14 +145,14 @@ impl<'a> Node<'a> { }; quote! { #bounds - pub _children: Vec<#children_type_name<'db>>, + pub _children: Vec, } } else { quote! {} } } - pub fn get_struct_tokens(&self) -> TokenStream { + pub fn get_struct_tokens(&self, subenums: &HashSet<&String>) -> TokenStream { let constructor = self.get_constructor(); let struct_fields = self .fields @@ -144,42 +161,31 @@ impl<'a> Node<'a> { .collect::>(); let children_field = self.get_children_field(); let name = format_ident!("{}", self.normalize_name()); - let trait_impls = self.get_trait_implementations(); + let trait_impls = self.get_trait_implementations(subenums); let derives = if self.config.serialize { let serialize_bounds = get_serialize_bounds(); quote! { - #[derive(Debug, Clone, Deserialize, Archive, Serialize, Drive, Eq, PartialEq, salsa::Update)] + #[derive(Debug, Deserialize, Clone, Archive, Serialize, Eq, PartialEq, salsa::Update)] #serialize_bounds } } else { quote! { - #[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] + #[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] } }; quote! { #derives pub struct #name<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, #children_field #(#struct_fields),* } @@ -189,8 +195,12 @@ impl<'a> Node<'a> { } fn get_children_constructor(&self) -> TokenStream { if self.has_children() { + let children_type_name = format_ident!("{}", self.children_struct_name()); quote! { - _children: named_children_without_field_names(db, node, buffer)? + let _children = named_children_without_field_names::, #children_type_name<'db>>(context, node)?; + for child in _children.iter().cloned() { + ids.push(child); + } } } else { quote! {} @@ -199,29 +209,35 @@ impl<'a> Node<'a> { pub fn get_constructor(&self) -> TokenStream { let name = format_ident!("{}", self.normalize_name()); let mut constructor_fields = Vec::new(); + let mut constructor_names = Vec::new(); for field in &self.fields { constructor_fields.push(field.get_constructor_field()); + constructor_names.push(format_ident!("{}", field.name())); } constructor_fields.push(self.get_children_constructor()); + if self.has_children() { + constructor_names.push(format_ident!("_children")); + } quote! { - impl<'db> FromNode<'db> for #name<'db> { - fn from_node(db: &'db dyn salsa::Database, node: tree_sitter::Node, buffer: &Arc) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { + impl<'db> FromNode<'db, NodeTypes<'db>> for #name<'db> { + fn from_node(context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + #(#constructor_fields)* + Ok((Self { start_byte: node.start_byte(), end_byte: node.end_byte(), - _kind: node.kind().to_string(), start_position: start_position, end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), + buffer: context.buffer.clone(), is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - #(#constructor_fields),* - }) + id, + file_id: context.file_id.clone(), + #(#constructor_names),* + }, ids)) } } } @@ -230,32 +246,45 @@ impl<'a> Node<'a> { let name = format_ident!("{}", self.normalize_name()); let children_type_name = self.children_struct_name(); - let children_type_ident = format_ident!("{}", children_type_name); - let mut children_type_generic = quote! {#children_type_ident}; + let children_type_generic; if children_type_name != "Self" { - children_type_generic = quote! {#children_type_generic<'db1>}; + let children_type_ident = format_ident!("{}Ref", children_type_name); + children_type_generic = quote! {#children_type_ident<'db2>}; + } else { + children_type_generic = quote! {#name<'db2>}; } let children_field = self.get_children_field_impl(); let children_by_field_name = self.get_children_by_field_name_impl(); let children_by_field_id = self.get_children_by_field_id_impl(); quote! { - impl<'db1> HasChildren<'db1> for #name<'db1> { - type Child = #children_type_generic; + impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for #name<'db1> { + type Child<'db2> = #children_type_generic where Self: 'db2; #children_field #children_by_field_name #children_by_field_id } } } - pub fn get_trait_implementations(&self) -> TokenStream { + pub fn get_trait_implementations(&self, subenums: &HashSet<&String>) -> TokenStream { let name = format_ident!("{}", self.normalize_name()); let children_impl = self.get_children_impl(); - + let getters = self + .fields + .iter() + .map(|f| f.get_field_getter(subenums)) + .collect::>(); + let kind_name = &self.raw.type_name; + let is_named = self.raw.named; + let kind_id = self.kind_id(); quote! { + impl<'db> #name<'db> { + const KIND_NAME: &'static str = #kind_name; + #(#getters)* + } impl<'db> CSTNode<'db> for #name<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -273,17 +302,20 @@ impl<'a> Node<'a> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + #kind_id } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + #is_named } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } #children_impl impl<'db> std::hash::Hash for #name<'db> { @@ -291,6 +323,22 @@ impl<'a> Node<'a> { self.id.hash(state); } } + impl<'db> PartialOrd for #name<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + impl<'db> Ord for #name<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } + } + } } fn get_children_field_impl(&self) -> TokenStream { @@ -298,7 +346,7 @@ impl<'a> Node<'a> { let num_children = self.get_children_names().len(); if num_children == 0 { return quote! { - fn children(&self) -> Vec { + fn children<'db2>(&'db2 self, context: &'db2 Tree< NodeTypes<'db2>>) -> Vec> { vec![] } }; @@ -310,7 +358,7 @@ impl<'a> Node<'a> { let children_init = if self.has_children() { quote! { - self._children.iter().cloned().collect() + self._children.iter().map(|c| context.get(c).unwrap().as_ref().try_into().unwrap()).collect() } } else { quote! { @@ -318,8 +366,8 @@ impl<'a> Node<'a> { } }; quote! { - fn children(&self) -> Vec { - let mut children: Vec<_> = #children_init; + fn children<'db2>(&'db2 self, context: &'db2 Tree< NodeTypes<'db2>>) -> Vec> { + let mut children: Vec> = #children_init; #(#children_fields;)* children.sort_by_key(|c| c.start_byte()); children @@ -335,7 +383,7 @@ impl<'a> Node<'a> { .collect::>(); quote! { - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>(&'db2 self, context: &'db2 Tree< NodeTypes<'db2>>, field_name: &str) -> Vec> { match field_name { #(#field_matches,)* _ => vec![], @@ -352,7 +400,7 @@ impl<'a> Node<'a> { .collect::>(); quote! { - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>(&'db2 self, context: &'db2 Tree< NodeTypes<'db2>>, field_id: u16) -> Vec> { match field_id { #(#field_matches,)* _ => vec![], @@ -434,11 +482,11 @@ mod tests { for subenum in &node.subenums { subenum_name_map.insert(subenum.clone(), normalize_type_name(subenum, true)); } - let tokens = node.get_enum_tokens(&subenum_name_map); + let tokens = node.get_enum_tokens(&subenum_name_map, false); insta::assert_debug_snapshot!(snapshot_tokens(&tokens)); node.add_subenum("subenum".to_string()); - let tokens = node.get_enum_tokens(&subenum_name_map); + let tokens = node.get_enum_tokens(&subenum_name_map, false); insta::assert_debug_snapshot!(snapshot_tokens(&tokens)); } @@ -447,7 +495,7 @@ mod tests { let raw_node = create_test_node("test_node"); let language = get_language_no_nodes(); let node = Node::new(Arc::new(raw_node), &language, Config::default()); - insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens())); + insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))); } #[test] @@ -468,7 +516,7 @@ mod tests { ); let language = get_language_no_nodes(); let node = Node::new(Arc::new(raw_node), &language, Config::default()); - insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens())); + insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))); } #[test] @@ -514,7 +562,7 @@ mod tests { let nodes = vec![raw_node.clone()]; let language = get_language(nodes); let node = Node::new(Arc::new(raw_node), &language, Config::default()); - insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens())); + insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))); } #[test_log::test] @@ -523,7 +571,7 @@ mod tests { create_test_node_with_children("test_node", vec!["child_type_a", "child_type_b"]); let language = get_language_no_nodes(); let node = Node::new(Arc::new(raw_node), &language, Config::default()); - insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens())); + insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))); } #[test] @@ -531,7 +579,7 @@ mod tests { let raw_node = create_test_node_with_children("test_node", vec!["child_type"]); let language = get_language_no_nodes(); let node = Node::new(Arc::new(raw_node), &language, Config::default()); - insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens())); + insta::assert_debug_snapshot!(snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))); } #[test] @@ -539,7 +587,9 @@ mod tests { let raw_node = create_test_node("test_node"); let language = get_language_no_nodes(); let node = Node::new(Arc::new(raw_node), &language, Config::default()); - insta::assert_debug_snapshot!(snapshot_tokens(&node.get_trait_implementations())); + insta::assert_debug_snapshot!(snapshot_tokens( + &node.get_trait_implementations(&HashSet::new()) + )); } #[test] diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-2.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-2.snap index 8aeda198..d92c07c0 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-2.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-2.snap @@ -2,4 +2,4 @@ source: codegen-sdk-cst-generator/src/generator/field.rs expression: snapshot_tokens(&optional_field.get_constructor_field()) --- -test_field : Box :: new (get_optional_child_by_field_name (db , & node , "test_field" , buffer) ?) +let test_field = get_optional_child_by_field_name :: < NodeTypes < 'db > , TestType < 'db >> (context , & node , "test_field") ? ; if let Some (child) = test_field . clone () { ids . push (child) ; } diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-3.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-3.snap index d46e6cd6..ba5b6b28 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-3.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field-3.snap @@ -2,4 +2,4 @@ source: codegen-sdk-cst-generator/src/generator/field.rs expression: snapshot_tokens(&multiple_field.get_constructor_field()) --- -test_field : get_multiple_children_by_field_name (db , & node , "test_field" , buffer) ? +let test_field = get_multiple_children_by_field_name :: < NodeTypes < 'db > , TestType < 'db >> (context , & node , "test_field") ? ; for child in test_field . iter () . cloned () { ids . push (child) ; } diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field.snap index 4e6146df..6ad98f92 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_constructor_field.snap @@ -2,4 +2,4 @@ source: codegen-sdk-cst-generator/src/generator/field.rs expression: snapshot_tokens(&field.get_constructor_field()) --- -test_field : Box :: new (get_child_by_field_name (db , & node , "test_field" , buffer) ?) +let test_field = get_child_by_field_name :: < NodeTypes < 'db > , TestType < 'db >> (context , & node , "test_field") ? ; ids . push (test_field . clone ()) ; diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-2.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-2.snap index 9895ee7c..8c4a46f7 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-2.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-2.snap @@ -2,4 +2,4 @@ source: codegen-sdk-cst-generator/src/generator/field.rs expression: snapshot_tokens(&optional_field.get_struct_field()) --- -pub test_field : Box < Option < TestType < 'db >> > +pub test_field : Option < indextree :: NodeId > diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-3.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-3.snap index 0b1e4b9b..68a0e453 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-3.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field-3.snap @@ -2,4 +2,4 @@ source: codegen-sdk-cst-generator/src/generator/field.rs expression: snapshot_tokens(&multiple_field.get_struct_field()) --- -pub test_field : Vec < TestType < 'db >> +pub test_field : Vec < indextree :: NodeId > diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field.snap index 09ab734f..2b859536 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__field__tests__get_struct_field.snap @@ -2,4 +2,4 @@ source: codegen-sdk-cst-generator/src/generator/field.rs expression: snapshot_tokens(&field.get_struct_field()) --- -pub test_field : Box < TestType < 'db >> +pub test_field : indextree :: NodeId diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_by_field_name_impl.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_by_field_name_impl.snap index c73b9d1e..b86ba5e0 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_by_field_name_impl.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_by_field_name_impl.snap @@ -2,13 +2,14 @@ source: codegen-sdk-cst-generator/src/generator/node.rs expression: snapshot_tokens(&node.get_children_by_field_name_impl()) --- -fn children_by_field_name(&self, field_name: &str) -> Vec { +fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, +) -> Vec> { match field_name { "test_field" => { - vec![ - Self::Child::try_from(NodeTypes::from(self.test_field.as_ref().clone())) - .unwrap() - ] + vec![context.get(& self.test_field).unwrap().as_ref().try_into().unwrap()] } _ => vec![], } diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_field_impl.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_field_impl.snap index e7e01eeb..0f2f54fc 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_field_impl.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_children_field_impl.snap @@ -2,13 +2,12 @@ source: codegen-sdk-cst-generator/src/generator/node.rs expression: snapshot_tokens(&node.get_children_field_impl()) --- -fn children(&self) -> Vec { - let mut children: Vec<_> = vec![]; - children - .push( - Self::Child::try_from(NodeTypes::from(self.test_field.as_ref().clone())) - .unwrap(), - ); +fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, +) -> Vec> { + let mut children: Vec> = vec![]; + children.push(context.get(&self.test_field).unwrap().as_ref().try_into().unwrap()); children.sort_by_key(|c| c.start_byte()); children } diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_complex.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_complex.snap index f6a95d76..a5dfaca2 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_complex.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_complex.snap @@ -1,70 +1,96 @@ --- source: codegen-sdk-cst-generator/src/generator/node.rs -expression: snapshot_tokens(&node.get_struct_tokens()) +expression: "snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))" --- -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct TestNode<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub multiple_field: Vec>, - pub optional_field: Box>>, - pub required_field: Box>, + pub multiple_field: Vec, + pub optional_field: Option, + pub required_field: indextree::NodeId, } -impl<'db> FromNode<'db> for TestNode<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for TestNode<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - multiple_field: get_multiple_children_by_field_name( - db, - &node, - "multiple_field", - buffer, - )?, - optional_field: Box::new( - get_optional_child_by_field_name(db, &node, "optional_field", buffer)?, - ), - required_field: Box::new( - get_child_by_field_name(db, &node, "required_field", buffer)?, - ), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let multiple_field = get_multiple_children_by_field_name::< + NodeTypes<'db>, + TestType<'db>, + >(context, &node, "multiple_field")?; + for child in multiple_field.iter().cloned() { + ids.push(child); + } + let optional_field = get_optional_child_by_field_name::< + NodeTypes<'db>, + TestType<'db>, + >(context, &node, "optional_field")?; + if let Some(child) = optional_field.clone() { + ids.push(child); + } + let required_field = get_child_by_field_name::< + NodeTypes<'db>, + TestType<'db>, + >(context, &node, "required_field")?; + ids.push(required_field.clone()); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + multiple_field, + optional_field, + required_field, + }, + ids, + )) + } +} +impl<'db> TestNode<'db> { + const KIND_NAME: &'static str = "test_node"; + pub fn multiple_field( + &self, + tree: &'db Tree>, + ) -> Vec<&TestType<'db>> { + self.multiple_field + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect() + } + pub fn optional_field( + &self, + tree: &'db Tree>, + ) -> Option<&TestType<'db>> { + if let Some(id) = self.optional_field { + Some(tree.get(&id).unwrap().as_ref().try_into().unwrap()) + } else { + None + } + } + pub fn required_field(&self, tree: &'db Tree>) -> &TestType<'db> { + tree.get(&self.required_field).unwrap().as_ref().try_into().unwrap() } } impl<'db> CSTNode<'db> for TestNode<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -82,52 +108,58 @@ impl<'db> CSTNode<'db> for TestNode<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for TestNode<'db1> { - type Child = TestNodeChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = vec![]; +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for TestNode<'db1> { + type Child<'db2> = TestNodeChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = vec![]; children .extend( self .multiple_field .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }), ); if let Some(child) = self.optional_field.as_ref() { - children - .push(Self::Child::try_from(NodeTypes::from(child.clone())).unwrap()); + children.push(context.get(child).unwrap().as_ref().try_into().unwrap()); } children .push( - Self::Child::try_from( - NodeTypes::from(self.required_field.as_ref().clone()), - ) - .unwrap(), + context.get(&self.required_field).unwrap().as_ref().try_into().unwrap(), ); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { "multiple_field" => { self.multiple_field .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }) .collect() } @@ -136,26 +168,30 @@ impl<'db1> HasChildren<'db1> for TestNode<'db1> { .as_ref() .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }) .collect() } "required_field" => { vec![ - Self::Child::try_from(NodeTypes::from(self.required_field.as_ref() - .clone())).unwrap() + context.get(& self.required_field).unwrap().as_ref().try_into() + .unwrap() ] } _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { 1u16 => { self.multiple_field .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }) .collect() } @@ -164,14 +200,14 @@ impl<'db1> HasChildren<'db1> for TestNode<'db1> { .as_ref() .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }) .collect() } 1u16 => { vec![ - Self::Child::try_from(NodeTypes::from(self.required_field.as_ref() - .clone())).unwrap() + context.get(& self.required_field).unwrap().as_ref().try_into() + .unwrap() ] } _ => vec![], @@ -183,3 +219,18 @@ impl<'db> std::hash::Hash for TestNode<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for TestNode<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for TestNode<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_simple.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_simple.snap index ffe3d5e9..3488e0ab 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_simple.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_simple.snap @@ -1,55 +1,49 @@ --- source: codegen-sdk-cst-generator/src/generator/node.rs -expression: snapshot_tokens(&node.get_struct_tokens()) +expression: "snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))" --- -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct TestNode<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for TestNode<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for TestNode<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> TestNode<'db> { + const KIND_NAME: &'static str = "test_node"; +} impl<'db> CSTNode<'db> for TestNode<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -67,29 +61,43 @@ impl<'db> CSTNode<'db> for TestNode<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for TestNode<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for TestNode<'db1> { + type Child<'db2> = TestNode<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -100,3 +108,18 @@ impl<'db> std::hash::Hash for TestNode<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for TestNode<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for TestNode<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_children.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_children.snap index 8b641ac5..71c16c87 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_children.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_children.snap @@ -1,57 +1,58 @@ --- source: codegen-sdk-cst-generator/src/generator/node.rs -expression: snapshot_tokens(&node.get_struct_tokens()) +expression: "snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))" --- -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct TestNode<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub _children: Vec>, + pub _children: Vec, } -impl<'db> FromNode<'db> for TestNode<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for TestNode<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - _children: named_children_without_field_names(db, node, buffer)?, - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let _children = named_children_without_field_names::< + NodeTypes<'db>, + TestNodeChildren<'db>, + >(context, node)?; + for child in _children.iter().cloned() { + ids.push(child); + } + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + _children, + }, + ids, + )) } } +impl<'db> TestNode<'db> { + const KIND_NAME: &'static str = "test_node"; +} impl<'db> CSTNode<'db> for TestNode<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -69,31 +70,49 @@ impl<'db> CSTNode<'db> for TestNode<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for TestNode<'db1> { - type Child = TestNodeChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = self._children.iter().cloned().collect(); +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for TestNode<'db1> { + type Child<'db2> = TestNodeChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = self + ._children + .iter() + .map(|c| context.get(c).unwrap().as_ref().try_into().unwrap()) + .collect(); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -104,3 +123,18 @@ impl<'db> std::hash::Hash for TestNode<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for TestNode<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for TestNode<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_fields.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_fields.snap index 65ebeccb..f2c05f62 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_fields.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_fields.snap @@ -1,59 +1,59 @@ --- source: codegen-sdk-cst-generator/src/generator/node.rs -expression: snapshot_tokens(&node.get_struct_tokens()) +expression: "snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))" --- -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct TestNode<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub test_field: Box>, + pub test_field: indextree::NodeId, } -impl<'db> FromNode<'db> for TestNode<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for TestNode<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - test_field: Box::new( - get_child_by_field_name(db, &node, "test_field", buffer)?, - ), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let test_field = get_child_by_field_name::< + NodeTypes<'db>, + TestType<'db>, + >(context, &node, "test_field")?; + ids.push(test_field.clone()); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + test_field, + }, + ids, + )) + } +} +impl<'db> TestNode<'db> { + const KIND_NAME: &'static str = "test_node"; + pub fn test_field(&self, tree: &'db Tree>) -> &TestType<'db> { + tree.get(&self.test_field).unwrap().as_ref().try_into().unwrap() } } impl<'db> CSTNode<'db> for TestNode<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -71,47 +71,56 @@ impl<'db> CSTNode<'db> for TestNode<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for TestNode<'db1> { - type Child = TestNodeChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = vec![]; +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for TestNode<'db1> { + type Child<'db2> = TestNodeChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = vec![]; children - .push( - Self::Child::try_from(NodeTypes::from(self.test_field.as_ref().clone())) - .unwrap(), - ); + .push(context.get(&self.test_field).unwrap().as_ref().try_into().unwrap()); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { "test_field" => { vec![ - Self::Child::try_from(NodeTypes::from(self.test_field.as_ref() - .clone())).unwrap() + context.get(& self.test_field).unwrap().as_ref().try_into().unwrap() ] } _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { 1u16 => { vec![ - Self::Child::try_from(NodeTypes::from(self.test_field.as_ref() - .clone())).unwrap() + context.get(& self.test_field).unwrap().as_ref().try_into().unwrap() ] } _ => vec![], @@ -123,3 +132,18 @@ impl<'db> std::hash::Hash for TestNode<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for TestNode<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for TestNode<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_single_child_type.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_single_child_type.snap index 8b641ac5..71c16c87 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_single_child_type.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_struct_tokens_with_single_child_type.snap @@ -1,57 +1,58 @@ --- source: codegen-sdk-cst-generator/src/generator/node.rs -expression: snapshot_tokens(&node.get_struct_tokens()) +expression: "snapshot_tokens(&node.get_struct_tokens(&HashSet::new()))" --- -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct TestNode<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub _children: Vec>, + pub _children: Vec, } -impl<'db> FromNode<'db> for TestNode<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for TestNode<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - _children: named_children_without_field_names(db, node, buffer)?, - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let _children = named_children_without_field_names::< + NodeTypes<'db>, + TestNodeChildren<'db>, + >(context, node)?; + for child in _children.iter().cloned() { + ids.push(child); + } + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + _children, + }, + ids, + )) } } +impl<'db> TestNode<'db> { + const KIND_NAME: &'static str = "test_node"; +} impl<'db> CSTNode<'db> for TestNode<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -69,31 +70,49 @@ impl<'db> CSTNode<'db> for TestNode<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for TestNode<'db1> { - type Child = TestNodeChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = self._children.iter().cloned().collect(); +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for TestNode<'db1> { + type Child<'db2> = TestNodeChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = self + ._children + .iter() + .map(|c| context.get(c).unwrap().as_ref().try_into().unwrap()) + .collect(); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -104,3 +123,18 @@ impl<'db> std::hash::Hash for TestNode<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for TestNode<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for TestNode<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_trait_implementations.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_trait_implementations.snap index c3a6f905..ffeb4bf2 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_trait_implementations.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__node__tests__get_trait_implementations.snap @@ -1,10 +1,13 @@ --- source: codegen-sdk-cst-generator/src/generator/node.rs -expression: snapshot_tokens(&node.get_trait_implementations()) +expression: "snapshot_tokens(&node.get_trait_implementations(&HashSet::new()))" --- +impl<'db> TestNode<'db> { + const KIND_NAME: &'static str = "test_node"; +} impl<'db> CSTNode<'db> for TestNode<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -22,29 +25,43 @@ impl<'db> CSTNode<'db> for TestNode<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for TestNode<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for TestNode<'db1> { + type Child<'db2> = TestNode<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -55,3 +72,18 @@ impl<'db> std::hash::Hash for TestNode<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for TestNode<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for TestNode<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums.snap index 6b78a583..b3cf6185 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums.snap @@ -3,7 +3,7 @@ source: codegen-sdk-cst-generator/src/generator/state.rs expression: snapshot_tokens(&enum_tokens) --- #[subenum(NodeCChildren, NodeCField)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(NodeCChildren, NodeCField)] @@ -27,14 +27,16 @@ impl<'db3> From> for NodeTypes<'db3> { Self::NodeC(node) } } -impl<'db4> FromNode<'db4> for NodeCChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for NodeCChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::NodeB(NodeB::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = NodeB::from_node(context, node)?; + Ok((Self::NodeB(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), @@ -44,14 +46,16 @@ impl<'db4> FromNode<'db4> for NodeCChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for NodeCField<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for NodeCField<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::NodeB(NodeB::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = NodeB::from_node(context, node)?; + Ok((Self::NodeB(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node-2.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node-2.snap index d2ce3d00..a6c909e5 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node-2.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node-2.snap @@ -2,54 +2,48 @@ source: codegen-sdk-cst-generator/src/generator/state.rs expression: snapshot_tokens(&struct_tokens) --- -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct AnonymousNodeA<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for AnonymousNodeA<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for AnonymousNodeA<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> AnonymousNodeA<'db> { + const KIND_NAME: &'static str = "node_a"; +} impl<'db> CSTNode<'db> for AnonymousNodeA<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -67,29 +61,43 @@ impl<'db> CSTNode<'db> for AnonymousNodeA<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + false } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for AnonymousNodeA<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for AnonymousNodeA<'db1> { + type Child<'db2> = AnonymousNodeA<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -100,54 +108,63 @@ impl<'db> std::hash::Hash for AnonymousNodeA<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for AnonymousNodeA<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for AnonymousNodeA<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct NodeB<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for NodeB<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for NodeB<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> NodeB<'db> { + const KIND_NAME: &'static str = "node_b"; +} impl<'db> CSTNode<'db> for NodeB<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -165,29 +182,43 @@ impl<'db> CSTNode<'db> for NodeB<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for NodeB<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for NodeB<'db1> { + type Child<'db2> = NodeB<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -198,56 +229,78 @@ impl<'db> std::hash::Hash for NodeB<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for NodeB<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for NodeB<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct NodeC<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub field: Vec>, + pub field: Vec, } -impl<'db> FromNode<'db> for NodeC<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for NodeC<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - field: get_multiple_children_by_field_name(db, &node, "field", buffer)?, - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let field = get_multiple_children_by_field_name::< + NodeTypes<'db>, + NodeCField<'db>, + >(context, &node, "field")?; + for child in field.iter().cloned() { + ids.push(child); + } + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + field, + }, + ids, + )) + } +} +impl<'db> NodeC<'db> { + const KIND_NAME: &'static str = "node_c"; + pub fn field(&self, tree: &'db Tree>) -> Vec> { + self.field + .iter() + .map(|id| tree.get(id).unwrap().as_ref().try_into().unwrap()) + .collect() } } impl<'db> CSTNode<'db> for NodeC<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -265,54 +318,68 @@ impl<'db> CSTNode<'db> for NodeC<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for NodeC<'db1> { - type Child = NodeCChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = vec![]; +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for NodeC<'db1> { + type Child<'db2> = NodeCChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = vec![]; children .extend( self .field .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }), ); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { "field" => { self.field .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }) .collect() } _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { 1u16 => { self.field .iter() .map(|child| { - Self::Child::try_from(NodeTypes::from(child.clone())).unwrap() + context.get(child).unwrap().as_ref().try_into().unwrap() }) .collect() } @@ -325,3 +392,18 @@ impl<'db> std::hash::Hash for NodeC<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for NodeC<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for NodeC<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node.snap index ccc1c455..9f04be32 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__add_field_subenums_missing_node.snap @@ -3,7 +3,7 @@ source: codegen-sdk-cst-generator/src/generator/state.rs expression: snapshot_tokens(&enum_tokens) --- #[subenum(NodeCChildren, NodeCField)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(NodeCChildren, NodeCField)] @@ -27,15 +27,15 @@ impl<'db3> From> for NodeTypes<'db3> { Self::NodeC(node) } } -impl<'db4> FromNode<'db4> for NodeCChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for NodeCChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok(Self::AnonymousNodeA(AnonymousNodeA::from_node(db, node, buffer)?)) + let (node, ids) = AnonymousNodeA::from_node(context, node)?; + Ok((Self::AnonymousNodeA(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -46,14 +46,16 @@ impl<'db4> FromNode<'db4> for NodeCChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for NodeCField<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for NodeCField<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::NodeB(NodeB::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = NodeB::from_node(context, node)?; + Ok((Self::NodeB(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_enum.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_enum.snap index fb15323e..74b0a68a 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_enum.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_enum.snap @@ -2,7 +2,7 @@ source: codegen-sdk-cst-generator/src/generator/state.rs expression: snapshot_tokens(&enum_tokens) --- -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { Test(Test<'db1>), diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_structs.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_structs.snap index 6274a6d6..5c0d90f7 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_structs.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__get_structs.snap @@ -2,54 +2,48 @@ source: codegen-sdk-cst-generator/src/generator/state.rs expression: snapshot_tokens(&struct_tokens) --- -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct Test<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for Test<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for Test<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> Test<'db> { + const KIND_NAME: &'static str = "test"; +} impl<'db> CSTNode<'db> for Test<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -67,29 +61,43 @@ impl<'db> CSTNode<'db> for Test<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for Test<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for Test<'db1> { + type Child<'db2> = Test<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -100,3 +108,18 @@ impl<'db> std::hash::Hash for Test<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for Test<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for Test<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children.snap index 6ccf3b66..6ea4e0cd 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children.snap @@ -3,7 +3,7 @@ source: codegen-sdk-cst-generator/src/generator/state.rs expression: snapshot_tokens(&enum_tokens) --- #[subenum(AnonymousTestChildren)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { AnonymousChild(AnonymousChild<'db1>), @@ -25,12 +25,11 @@ impl<'db3> From> for NodeTypes<'db3> { Self::AnonymousTest(node) } } -impl<'db4> FromNode<'db4> for AnonymousTestChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for AnonymousTestChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { _ => { Err(ParseError::UnexpectedNode { diff --git a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children_subtypes.snap b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children_subtypes.snap index a327e4ea..08c4f396 100644 --- a/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children_subtypes.snap +++ b/codegen-sdk-cst-generator/src/generator/snapshots/codegen_sdk_cst_generator__generator__state__tests__parse_children_subtypes.snap @@ -3,7 +3,7 @@ source: codegen-sdk-cst-generator/src/generator/state.rs expression: snapshot_tokens(&enum_tokens) --- #[subenum(AnonymousClassChildren, Definition)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { AnonymousClass(AnonymousClass<'db1>), @@ -19,12 +19,11 @@ impl<'db3> From> for NodeTypes<'db3> { Self::AnonymousFunction(node) } } -impl<'db4> FromNode<'db4> for AnonymousClassChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for AnonymousClassChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { _ => { Err(ParseError::UnexpectedNode { @@ -35,12 +34,11 @@ impl<'db4> FromNode<'db4> for AnonymousClassChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for Definition<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Definition<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { _ => { Err(ParseError::UnexpectedNode { diff --git a/codegen-sdk-cst-generator/src/generator/state.rs b/codegen-sdk-cst-generator/src/generator/state.rs index 263ea4c9..abb2208f 100644 --- a/codegen-sdk-cst-generator/src/generator/state.rs +++ b/codegen-sdk-cst-generator/src/generator/state.rs @@ -1,5 +1,5 @@ use std::{ - collections::{BTreeMap, BTreeSet, HashMap, VecDeque}, + collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque}, sync::Arc, }; @@ -16,7 +16,7 @@ use crate::{ Config, generator::{ constants::TYPE_NAME, - utils::{get_comment_type, get_from_node, get_from_type}, + utils::{get_comment_type, get_from_enum_to_ref, get_from_node, get_from_type}, }, }; #[derive(Debug)] @@ -146,14 +146,17 @@ impl<'a> State<'a> { node.add_subenum(name.to_string()); } } else { - let variants = self.get_variants(&node.type_name); + let variants = self.get_variants(&node.type_name, true); self.add_subenum(name, &variants.iter().collect()); } } } - pub fn get_variants(&self, subenum: &str) -> Vec { - let comment = get_comment_type(); - let mut variants = vec![comment]; + pub fn get_variants(&self, subenum: &str, include_comment: bool) -> Vec { + let mut variants = Vec::new(); + if include_comment { + let comment = get_comment_type(); + variants.push(comment); + } for node in self.nodes.values() { log::debug!("Checking subenum: {} for {}", subenum, node.kind()); if node.subenums.contains(&subenum.to_string()) { @@ -172,7 +175,10 @@ impl<'a> State<'a> { variant_map.insert( node.kind_id(), quote! { - Ok(Self::#variant_name(#variant_name::from_node(db, node, buffer)?)) + { + let (node, ids) = #variant_name::from_node(context, node)?; + Ok((Self::#variant_name(node), ids)) + } }, ); } @@ -185,7 +191,7 @@ impl<'a> State<'a> { get_from_node(enum_name, true, &variant_map) } // Get the overarching enum for the nodes - pub fn get_enum(&self) -> TokenStream { + pub fn get_enum(&self, is_ref: bool) -> TokenStream { let mut enum_tokens = Vec::new(); let mut from_tokens = TokenStream::new(); let mut subenums = Vec::new(); @@ -193,18 +199,41 @@ impl<'a> State<'a> { for name in self.subenums.iter() { subenum_name_map.insert(name.clone(), normalize_type_name(name, true)); } + let enum_name = if is_ref { + format_ident!("{}Ref", TYPE_NAME) + } else { + format_ident!("{}", TYPE_NAME) + }; for node in self.nodes.values() { - enum_tokens.push(node.get_enum_tokens(&subenum_name_map)); - from_tokens.extend_one(get_from_type(&node.normalize_name())); + enum_tokens.push(node.get_enum_tokens(&subenum_name_map, is_ref)); + from_tokens.extend_one(get_from_type(&node.normalize_name(), &enum_name, is_ref)); + } + if is_ref { + let variants = self.get_node_struct_names(); + let ref_convert = get_from_enum_to_ref(&TYPE_NAME, &variants); + from_tokens.extend_one(ref_convert); } for subenum in self.subenums.iter() { assert!( - self.get_variants(subenum).len() > 0, + self.get_variants(subenum, true).len() > 0, "Subenum {} has no variants", subenum ); - from_tokens.extend_one(self.get_from_node(subenum)); - subenums.push(format_ident!("{}", normalize_type_name(&subenum, true))); + if is_ref { + let normalized_subenum = normalize_type_name(&subenum, true); + let ref_name = format_ident!("{}Ref", normalized_subenum); + subenums.push(ref_name); + let variants = self + .get_variants(subenum, false) + .into_iter() + .map(|v| v.ident()) + .collect(); + let ref_convert = get_from_enum_to_ref(&normalized_subenum, &variants); + from_tokens.extend_one(ref_convert); + } else { + from_tokens.extend_one(self.get_from_node(subenum)); + subenums.push(format_ident!("{}", normalize_type_name(&subenum, true))); + } } let subenum_tokens = if !subenums.is_empty() { subenums.sort(); @@ -221,13 +250,21 @@ impl<'a> State<'a> { } else { quote! {} }; - let enum_name = format_ident!("{}", TYPE_NAME); + let derive_header = if is_ref { + quote! { + #[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)] + } + } else { + quote! { + #[derive(Debug, Eq, PartialEq,Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] + #[delegate( + CSTNode<'db1> + )] + } + }; quote! { #subenum_tokens - #[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] - #[delegate( - CSTNode<'db1> - )] + #derive_header pub enum #enum_name<'db1> { #(#enum_tokens),* } @@ -236,8 +273,9 @@ impl<'a> State<'a> { } pub fn get_structs(&self) -> TokenStream { let mut struct_tokens = TokenStream::new(); + let subenums = HashSet::from_iter(self.subenums.iter()); for node in self.nodes.values() { - struct_tokens.extend_one(node.get_struct_tokens()); + struct_tokens.extend_one(node.get_struct_tokens(&subenums)); } struct_tokens } @@ -253,7 +291,7 @@ impl<'a> State<'a> { None } pub fn get_subenum_variants(&self, name: &str) -> Vec<&Node<'a>> { - let variants = self.get_variants(name); + let variants = self.get_variants(name, true); let mut nodes = Vec::new(); for variant in variants { if let Some(node) = self.get_node_for_struct_name(&variant.normalize()) { @@ -295,7 +333,7 @@ mod tests { let nodes = vec![node]; let language = get_language(nodes); let state = State::new(&language, Config::default()); - let enum_tokens = state.get_enum(); + let enum_tokens = state.get_enum(false); insta::assert_debug_snapshot!(snapshot_tokens(&enum_tokens)); } #[test_log::test] @@ -340,7 +378,7 @@ mod tests { let nodes = vec![child, child_two, node]; let language = get_language(nodes); let state = State::new(&language, Config::default()); - let enum_tokens = state.get_enum(); + let enum_tokens = state.get_enum(false); insta::assert_debug_snapshot!(snapshot_tokens(&enum_tokens)); } #[test_log::test] @@ -388,7 +426,7 @@ mod tests { let nodes = vec![definition, class, function]; let language = get_language(nodes); let state = State::new(&language, Config::default()); - let enum_tokens = state.get_enum(); + let enum_tokens = state.get_enum(false); insta::assert_debug_snapshot!(snapshot_tokens(&enum_tokens)); } #[test_log::test] @@ -436,7 +474,7 @@ mod tests { let nodes = vec![node_a, node_b, node_c]; let language = get_language(nodes); let state = State::new(&language, Config::default()); - let enum_tokens = state.get_enum(); + let enum_tokens = state.get_enum(false); insta::assert_debug_snapshot!(snapshot_tokens(&enum_tokens)); } #[test_log::test] @@ -476,7 +514,7 @@ mod tests { let nodes = vec![node_a, node_c]; let language = get_language(nodes); let state = State::new(&language, Config::default()); - let enum_tokens = state.get_enum(); + let enum_tokens = state.get_enum(false); let struct_tokens = state.get_structs(); insta::assert_debug_snapshot!(snapshot_tokens(&enum_tokens)); insta::assert_debug_snapshot!(snapshot_tokens(&struct_tokens)); @@ -536,7 +574,7 @@ mod tests { let language = get_language(nodes); let state = State::new(&language, Config::default()); - let variants = state.get_variants("parent"); + let variants = state.get_variants("parent", true); assert_eq!( vec![ TypeDefinition { diff --git a/codegen-sdk-cst-generator/src/generator/utils.rs b/codegen-sdk-cst-generator/src/generator/utils.rs index 7db00569..1dbf87fd 100644 --- a/codegen-sdk-cst-generator/src/generator/utils.rs +++ b/codegen-sdk-cst-generator/src/generator/utils.rs @@ -3,8 +3,9 @@ use std::collections::BTreeMap; use codegen_sdk_common::{naming::normalize_type_name, parser::TypeDefinition}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use syn::Ident; -use super::constants::TYPE_NAME; +use crate::generator::constants::TYPE_NAME_REF; pub fn get_serialize_bounds() -> TokenStream { quote! { #[rkyv(serialize_bounds( @@ -20,17 +21,69 @@ pub fn get_serialize_bounds() -> TokenStream { ))] } } -pub fn get_from_type(struct_name: &str) -> TokenStream { - let name = format_ident!("{}", struct_name); - let target = format_ident!("{}", TYPE_NAME); + +pub fn get_from_type(struct_name: &str, target: &Ident, is_ref: bool) -> TokenStream { + let name_ident = format_ident!("{}", struct_name); + let name = if is_ref { + quote! { &'db3 #name_ident } + } else { + quote! { #name_ident } + }; + quote! { impl<'db3> From<#name<'db3>> for #target<'db3> { fn from(node: #name<'db3>) -> Self { - Self::#name(node) + Self::#name_ident(node) + } + } + } +} +pub fn get_from_enum_to_ref(enum_name: &str, variant_names: &Vec) -> TokenStream { + let name = format_ident!("{}", enum_name); + let name_ref = format_ident!("{}Ref", enum_name); + let node_types_ref = format_ident!("{}", TYPE_NAME_REF); + + quote! { + impl<'db3> #name<'db3> { + pub fn as_ref(&'db3 self) -> #name_ref<'db3> { + match self { + #(Self::#variant_names(data) => #name_ref::#variant_names(data),)* + } + } + } + #[delegate_to_methods] + #[delegate(CSTNode<'db3>, target_ref = "deref")] + impl<'db3> #name_ref<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + #(Self::#variant_names(data) => *data,)* + } } } + impl<'db3> From<&'db3 #name<'db3>> for #node_types_ref<'db3> { + fn from(node: &'db3 #name<'db3>) -> Self { + node.as_ref().into() + } + } + #( + impl<'db3> TryFrom<#name_ref<'db3>> for &'db3 #variant_names<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: #name_ref<'db3>) -> Result { + if let #name_ref::#variant_names(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } + } + )* } } + pub fn get_from_node( node: &str, named: bool, @@ -44,8 +97,8 @@ pub fn get_from_node( values.push(value); } quote! { - impl<'db4> FromNode<'db4> for #node<'db4> { - fn from_node(db: &'db4 dyn salsa::Database, node: tree_sitter::Node, buffer: &Arc) -> Result { + impl<'db4> FromNode<'db4, NodeTypes<'db4>> for #node<'db4> { + fn from_node(context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node) -> Result<(Self, Vec), ParseError> { match node.kind_id() { #(#keys => #values,)* _ => Err(ParseError::UnexpectedNode { diff --git a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__basic_subtypes.snap b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__basic_subtypes.snap index 0fd5bd5c..487887b6 100644 --- a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__basic_subtypes.snap +++ b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__basic_subtypes.snap @@ -8,11 +8,14 @@ use codegen_sdk_common::*; use subenum::subenum; use std::backtrace::Backtrace; use bytes::Bytes; -use derive_generic_visitor::Drive; use ambassador::Delegate; +use derive_more::Debug; +use ambassador::delegate_to_methods; use codegen_sdk_cst::CSTLanguage; +use crate::cst::tree::ParseContext; +use std::path::PathBuf; #[subenum(Expression)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(Expression)] @@ -30,15 +33,15 @@ impl<'db3> From> for NodeTypes<'db3> { Self::UnaryExpression(node) } } -impl<'db4> FromNode<'db4> for Expression<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Expression<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok(Self::UnaryExpression(UnaryExpression::from_node(db, node, buffer)?)) + let (node, ids) = UnaryExpression::from_node(context, node)?; + Ok((Self::UnaryExpression(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -49,54 +52,168 @@ impl<'db4> FromNode<'db4> for Expression<'db4> { } } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[subenum(ExpressionRef)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)] +pub enum NodeTypesRef<'db1> { + #[subenum(ExpressionRef)] + BinaryExpression(&'db1 BinaryExpression<'db1>), + #[subenum(ExpressionRef)] + UnaryExpression(&'db1 UnaryExpression<'db1>), +} +impl<'db3> From<&'db3 BinaryExpression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 BinaryExpression<'db3>) -> Self { + Self::BinaryExpression(node) + } +} +impl<'db3> From<&'db3 UnaryExpression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 UnaryExpression<'db3>) -> Self { + Self::UnaryExpression(node) + } +} +impl<'db3> NodeTypes<'db3> { + pub fn as_ref(&'db3 self) -> NodeTypesRef<'db3> { + match self { + Self::BinaryExpression(data) => NodeTypesRef::BinaryExpression(data), + Self::UnaryExpression(data) => NodeTypesRef::UnaryExpression(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> NodeTypesRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::UnaryExpression(data) => *data, + } + } +} +impl<'db3> From<&'db3 NodeTypes<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 NodeTypes<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 UnaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::UnaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> Expression<'db3> { + pub fn as_ref(&'db3 self) -> ExpressionRef<'db3> { + match self { + Self::BinaryExpression(data) => ExpressionRef::BinaryExpression(data), + Self::UnaryExpression(data) => ExpressionRef::UnaryExpression(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> ExpressionRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::UnaryExpression(data) => *data, + } + } +} +impl<'db3> From<&'db3 Expression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Expression<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: ExpressionRef<'db3>) -> Result { + if let ExpressionRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 UnaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: ExpressionRef<'db3>) -> Result { + if let ExpressionRef::UnaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct BinaryExpression<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for BinaryExpression<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for BinaryExpression<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> BinaryExpression<'db> { + const KIND_NAME: &'static str = "binary_expression"; +} impl<'db> CSTNode<'db> for BinaryExpression<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -114,29 +231,43 @@ impl<'db> CSTNode<'db> for BinaryExpression<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for BinaryExpression<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for BinaryExpression<'db1> { + type Child<'db2> = BinaryExpression<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -147,54 +278,63 @@ impl<'db> std::hash::Hash for BinaryExpression<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for BinaryExpression<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for BinaryExpression<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct UnaryExpression<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for UnaryExpression<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for UnaryExpression<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> UnaryExpression<'db> { + const KIND_NAME: &'static str = "unary_expression"; +} impl<'db> CSTNode<'db> for UnaryExpression<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -212,29 +352,43 @@ impl<'db> CSTNode<'db> for UnaryExpression<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for UnaryExpression<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for UnaryExpression<'db1> { + type Child<'db2> = UnaryExpression<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -245,16 +399,37 @@ impl<'db> std::hash::Hash for UnaryExpression<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for UnaryExpression<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for UnaryExpression<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +impl<'db> TreeNode for NodeTypes<'db> {} #[salsa::tracked] pub struct Parsed<'db> { + #[id] + id: FileNodeId<'db>, #[tracked] #[return_ref] - pub program: Option>, + #[no_clone] + pub tree: Tree>, + pub program: indextree::NodeId, } -pub fn parse_program_raw( - db: &dyn salsa::Database, +pub fn parse_program_raw<'db>( + db: &'db dyn salsa::Database, input: codegen_sdk_cst::Input, -) -> Option> { + path: PathBuf, +) -> Option> { let buffer = Bytes::from(input.content(db).as_bytes().to_vec()); let tree = codegen_sdk_common::language::language::Language .parse_tree_sitter(&input.content(db)); @@ -264,15 +439,20 @@ pub fn parse_program_raw( ParseError::SyntaxError.report(db); None } else { - let buffer = Arc::new(buffer); - Program::from_node(db, tree.root_node(), &buffer) + let mut context = ParseContext::new(db, path, buffer); + let root_id = Program::orphaned(&mut context, tree.root_node()) .map_or_else( |e| { e.report(db); None }, |program| { Some(program) }, - ) + ); + if let Some(program) = root_id { + Some(Parsed::new(db, context.file_id, context.tree, program)) + } else { + None + } } } Err(e) => { @@ -281,15 +461,21 @@ pub fn parse_program_raw( } } } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn parse_program( db: &dyn salsa::Database, input: codegen_sdk_cst::Input, ) -> Parsed<'_> { - Parsed::new(db, parse_program_raw(db, input)) + let raw = parse_program_raw(db, input, std::path::PathBuf::new()); + if let Some(parsed) = raw { + parsed + } else { + panic!("Failed to parse program"); + } } pub struct Language; impl CSTLanguage for Language { + type Types<'db> = NodeTypes<'db>; type Program<'db> = Program<'db>; fn language() -> &'static codegen_sdk_common::language::Language { &codegen_sdk_common::language::language::Language @@ -297,8 +483,12 @@ impl CSTLanguage for Language { fn parse<'db>( db: &'db dyn salsa::Database, content: std::string::String, - ) -> &'db Option> { + ) -> Option<(&'db Self::Program<'db>, &'db Tree>)> { let input = codegen_sdk_cst::Input::new(db, content); - return parse_program(db, input).program(db); + let parsed = parse_program(db, input); + let program = parsed.program(db); + let tree = parsed.tree(db); + let program = tree.get(&program).unwrap().as_ref(); + Some((program.try_into().unwrap(), tree)) } } diff --git a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__deeply_nested_subtypes.snap b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__deeply_nested_subtypes.snap index bf3e95c7..55f053b2 100644 --- a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__deeply_nested_subtypes.snap +++ b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__deeply_nested_subtypes.snap @@ -8,11 +8,14 @@ use codegen_sdk_common::*; use subenum::subenum; use std::backtrace::Backtrace; use bytes::Bytes; -use derive_generic_visitor::Drive; use ambassador::Delegate; +use derive_more::Debug; +use ambassador::delegate_to_methods; use codegen_sdk_cst::CSTLanguage; +use crate::cst::tree::ParseContext; +use std::path::PathBuf; #[subenum(Declaration, FunctionDeclaration, Statement)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(Declaration, Statement)] @@ -37,19 +40,15 @@ impl<'db3> From> for NodeTypes<'db3> { Self::MethodDeclaration(node) } } -impl<'db4> FromNode<'db4> for Declaration<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Declaration<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok( - Self::MethodDeclaration( - MethodDeclaration::from_node(db, node, buffer)?, - ), - ) + let (node, ids) = MethodDeclaration::from_node(context, node)?; + Ok((Self::MethodDeclaration(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -60,19 +59,15 @@ impl<'db4> FromNode<'db4> for Declaration<'db4> { } } } -impl<'db4> FromNode<'db4> for FunctionDeclaration<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for FunctionDeclaration<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok( - Self::MethodDeclaration( - MethodDeclaration::from_node(db, node, buffer)?, - ), - ) + let (node, ids) = MethodDeclaration::from_node(context, node)?; + Ok((Self::MethodDeclaration(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -83,19 +78,15 @@ impl<'db4> FromNode<'db4> for FunctionDeclaration<'db4> { } } } -impl<'db4> FromNode<'db4> for Statement<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Statement<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok( - Self::MethodDeclaration( - MethodDeclaration::from_node(db, node, buffer)?, - ), - ) + let (node, ids) = MethodDeclaration::from_node(context, node)?; + Ok((Self::MethodDeclaration(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -106,54 +97,295 @@ impl<'db4> FromNode<'db4> for Statement<'db4> { } } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[subenum(DeclarationRef, FunctionDeclarationRef, StatementRef)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)] +pub enum NodeTypesRef<'db1> { + #[subenum(DeclarationRef, StatementRef)] + ClassDeclaration(&'db1 ClassDeclaration<'db1>), + #[subenum(StatementRef)] + ExpressionStatement(&'db1 ExpressionStatement<'db1>), + #[subenum(FunctionDeclarationRef, DeclarationRef, StatementRef)] + MethodDeclaration(&'db1 MethodDeclaration<'db1>), +} +impl<'db3> From<&'db3 ClassDeclaration<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 ClassDeclaration<'db3>) -> Self { + Self::ClassDeclaration(node) + } +} +impl<'db3> From<&'db3 ExpressionStatement<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 ExpressionStatement<'db3>) -> Self { + Self::ExpressionStatement(node) + } +} +impl<'db3> From<&'db3 MethodDeclaration<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 MethodDeclaration<'db3>) -> Self { + Self::MethodDeclaration(node) + } +} +impl<'db3> NodeTypes<'db3> { + pub fn as_ref(&'db3 self) -> NodeTypesRef<'db3> { + match self { + Self::ClassDeclaration(data) => NodeTypesRef::ClassDeclaration(data), + Self::ExpressionStatement(data) => NodeTypesRef::ExpressionStatement(data), + Self::MethodDeclaration(data) => NodeTypesRef::MethodDeclaration(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> NodeTypesRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::ClassDeclaration(data) => *data, + Self::ExpressionStatement(data) => *data, + Self::MethodDeclaration(data) => *data, + } + } +} +impl<'db3> From<&'db3 NodeTypes<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 NodeTypes<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 ClassDeclaration<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::ClassDeclaration(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 ExpressionStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::ExpressionStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 MethodDeclaration<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::MethodDeclaration(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> Declaration<'db3> { + pub fn as_ref(&'db3 self) -> DeclarationRef<'db3> { + match self { + Self::ClassDeclaration(data) => DeclarationRef::ClassDeclaration(data), + Self::MethodDeclaration(data) => DeclarationRef::MethodDeclaration(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> DeclarationRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::ClassDeclaration(data) => *data, + Self::MethodDeclaration(data) => *data, + } + } +} +impl<'db3> From<&'db3 Declaration<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Declaration<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 ClassDeclaration<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: DeclarationRef<'db3>) -> Result { + if let DeclarationRef::ClassDeclaration(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 MethodDeclaration<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: DeclarationRef<'db3>) -> Result { + if let DeclarationRef::MethodDeclaration(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> FunctionDeclaration<'db3> { + pub fn as_ref(&'db3 self) -> FunctionDeclarationRef<'db3> { + match self { + Self::MethodDeclaration(data) => { + FunctionDeclarationRef::MethodDeclaration(data) + } + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> FunctionDeclarationRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::MethodDeclaration(data) => *data, + } + } +} +impl<'db3> From<&'db3 FunctionDeclaration<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 FunctionDeclaration<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 MethodDeclaration<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: FunctionDeclarationRef<'db3>) -> Result { + if let FunctionDeclarationRef::MethodDeclaration(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> Statement<'db3> { + pub fn as_ref(&'db3 self) -> StatementRef<'db3> { + match self { + Self::ClassDeclaration(data) => StatementRef::ClassDeclaration(data), + Self::ExpressionStatement(data) => StatementRef::ExpressionStatement(data), + Self::MethodDeclaration(data) => StatementRef::MethodDeclaration(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> StatementRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::ClassDeclaration(data) => *data, + Self::ExpressionStatement(data) => *data, + Self::MethodDeclaration(data) => *data, + } + } +} +impl<'db3> From<&'db3 Statement<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Statement<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 ClassDeclaration<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: StatementRef<'db3>) -> Result { + if let StatementRef::ClassDeclaration(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 ExpressionStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: StatementRef<'db3>) -> Result { + if let StatementRef::ExpressionStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 MethodDeclaration<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: StatementRef<'db3>) -> Result { + if let StatementRef::MethodDeclaration(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct ClassDeclaration<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for ClassDeclaration<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for ClassDeclaration<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> ClassDeclaration<'db> { + const KIND_NAME: &'static str = "class_declaration"; +} impl<'db> CSTNode<'db> for ClassDeclaration<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -171,29 +403,43 @@ impl<'db> CSTNode<'db> for ClassDeclaration<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for ClassDeclaration<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for ClassDeclaration<'db1> { + type Child<'db2> = ClassDeclaration<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -204,54 +450,63 @@ impl<'db> std::hash::Hash for ClassDeclaration<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for ClassDeclaration<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for ClassDeclaration<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct ExpressionStatement<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for ExpressionStatement<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for ExpressionStatement<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> ExpressionStatement<'db> { + const KIND_NAME: &'static str = "expression_statement"; +} impl<'db> CSTNode<'db> for ExpressionStatement<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -269,29 +524,43 @@ impl<'db> CSTNode<'db> for ExpressionStatement<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for ExpressionStatement<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for ExpressionStatement<'db1> { + type Child<'db2> = ExpressionStatement<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -302,54 +571,63 @@ impl<'db> std::hash::Hash for ExpressionStatement<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for ExpressionStatement<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for ExpressionStatement<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct MethodDeclaration<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for MethodDeclaration<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for MethodDeclaration<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> MethodDeclaration<'db> { + const KIND_NAME: &'static str = "method_declaration"; +} impl<'db> CSTNode<'db> for MethodDeclaration<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -367,29 +645,43 @@ impl<'db> CSTNode<'db> for MethodDeclaration<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for MethodDeclaration<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for MethodDeclaration<'db1> { + type Child<'db2> = MethodDeclaration<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -400,16 +692,37 @@ impl<'db> std::hash::Hash for MethodDeclaration<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for MethodDeclaration<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for MethodDeclaration<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +impl<'db> TreeNode for NodeTypes<'db> {} #[salsa::tracked] pub struct Parsed<'db> { + #[id] + id: FileNodeId<'db>, #[tracked] #[return_ref] - pub program: Option>, + #[no_clone] + pub tree: Tree>, + pub program: indextree::NodeId, } -pub fn parse_program_raw( - db: &dyn salsa::Database, +pub fn parse_program_raw<'db>( + db: &'db dyn salsa::Database, input: codegen_sdk_cst::Input, -) -> Option> { + path: PathBuf, +) -> Option> { let buffer = Bytes::from(input.content(db).as_bytes().to_vec()); let tree = codegen_sdk_common::language::language::Language .parse_tree_sitter(&input.content(db)); @@ -419,15 +732,20 @@ pub fn parse_program_raw( ParseError::SyntaxError.report(db); None } else { - let buffer = Arc::new(buffer); - Program::from_node(db, tree.root_node(), &buffer) + let mut context = ParseContext::new(db, path, buffer); + let root_id = Program::orphaned(&mut context, tree.root_node()) .map_or_else( |e| { e.report(db); None }, |program| { Some(program) }, - ) + ); + if let Some(program) = root_id { + Some(Parsed::new(db, context.file_id, context.tree, program)) + } else { + None + } } } Err(e) => { @@ -436,15 +754,21 @@ pub fn parse_program_raw( } } } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn parse_program( db: &dyn salsa::Database, input: codegen_sdk_cst::Input, ) -> Parsed<'_> { - Parsed::new(db, parse_program_raw(db, input)) + let raw = parse_program_raw(db, input, std::path::PathBuf::new()); + if let Some(parsed) = raw { + parsed + } else { + panic!("Failed to parse program"); + } } pub struct Language; impl CSTLanguage for Language { + type Types<'db> = NodeTypes<'db>; type Program<'db> = Program<'db>; fn language() -> &'static codegen_sdk_common::language::Language { &codegen_sdk_common::language::language::Language @@ -452,8 +776,12 @@ impl CSTLanguage for Language { fn parse<'db>( db: &'db dyn salsa::Database, content: std::string::String, - ) -> &'db Option> { + ) -> Option<(&'db Self::Program<'db>, &'db Tree>)> { let input = codegen_sdk_cst::Input::new(db, content); - return parse_program(db, input).program(db); + let parsed = parse_program(db, input); + let program = parsed.program(db); + let tree = parsed.tree(db); + let program = tree.get(&program).unwrap().as_ref(); + Some((program.try_into().unwrap(), tree)) } } diff --git a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__subtypes_with_fields.snap b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__subtypes_with_fields.snap index cb0a44f6..30c03a16 100644 --- a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__subtypes_with_fields.snap +++ b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes__subtypes_with_fields.snap @@ -8,11 +8,14 @@ use codegen_sdk_common::*; use subenum::subenum; use std::backtrace::Backtrace; use bytes::Bytes; -use derive_generic_visitor::Drive; use ambassador::Delegate; +use derive_more::Debug; +use ambassador::delegate_to_methods; use codegen_sdk_cst::CSTLanguage; +use crate::cst::tree::ParseContext; +use std::path::PathBuf; #[subenum(BinaryExpressionChildren, Expression)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(Expression, BinaryExpressionChildren)] @@ -30,14 +33,16 @@ impl<'db3> From> for NodeTypes<'db3> { Self::Literal(node) } } -impl<'db4> FromNode<'db4> for BinaryExpressionChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for BinaryExpressionChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::Literal(Literal::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = Literal::from_node(context, node)?; + Ok((Self::Literal(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), @@ -47,14 +52,16 @@ impl<'db4> FromNode<'db4> for BinaryExpressionChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for Expression<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Expression<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::Literal(Literal::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = Literal::from_node(context, node)?; + Ok((Self::Literal(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), @@ -64,58 +71,241 @@ impl<'db4> FromNode<'db4> for Expression<'db4> { } } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[subenum(BinaryExpressionChildrenRef, ExpressionRef)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)] +pub enum NodeTypesRef<'db1> { + #[subenum(ExpressionRef, BinaryExpressionChildrenRef)] + BinaryExpression(&'db1 BinaryExpression<'db1>), + #[subenum(ExpressionRef, BinaryExpressionChildrenRef)] + Literal(&'db1 Literal<'db1>), +} +impl<'db3> From<&'db3 BinaryExpression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 BinaryExpression<'db3>) -> Self { + Self::BinaryExpression(node) + } +} +impl<'db3> From<&'db3 Literal<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Literal<'db3>) -> Self { + Self::Literal(node) + } +} +impl<'db3> NodeTypes<'db3> { + pub fn as_ref(&'db3 self) -> NodeTypesRef<'db3> { + match self { + Self::BinaryExpression(data) => NodeTypesRef::BinaryExpression(data), + Self::Literal(data) => NodeTypesRef::Literal(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> NodeTypesRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::Literal(data) => *data, + } + } +} +impl<'db3> From<&'db3 NodeTypes<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 NodeTypes<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 Literal<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::Literal(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> BinaryExpressionChildren<'db3> { + pub fn as_ref(&'db3 self) -> BinaryExpressionChildrenRef<'db3> { + match self { + Self::BinaryExpression(data) => { + BinaryExpressionChildrenRef::BinaryExpression(data) + } + Self::Literal(data) => BinaryExpressionChildrenRef::Literal(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> BinaryExpressionChildrenRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::Literal(data) => *data, + } + } +} +impl<'db3> From<&'db3 BinaryExpressionChildren<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 BinaryExpressionChildren<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: BinaryExpressionChildrenRef<'db3>) -> Result { + if let BinaryExpressionChildrenRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 Literal<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: BinaryExpressionChildrenRef<'db3>) -> Result { + if let BinaryExpressionChildrenRef::Literal(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> Expression<'db3> { + pub fn as_ref(&'db3 self) -> ExpressionRef<'db3> { + match self { + Self::BinaryExpression(data) => ExpressionRef::BinaryExpression(data), + Self::Literal(data) => ExpressionRef::Literal(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> ExpressionRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::Literal(data) => *data, + } + } +} +impl<'db3> From<&'db3 Expression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Expression<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: ExpressionRef<'db3>) -> Result { + if let ExpressionRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 Literal<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: ExpressionRef<'db3>) -> Result { + if let ExpressionRef::Literal(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct BinaryExpression<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub left: Box>, - pub right: Box>, -} -impl<'db> FromNode<'db> for BinaryExpression<'db> { + pub left: indextree::NodeId, + pub right: indextree::NodeId, +} +impl<'db> FromNode<'db, NodeTypes<'db>> for BinaryExpression<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - left: Box::new(get_child_by_field_name(db, &node, "left", buffer)?), - right: Box::new(get_child_by_field_name(db, &node, "right", buffer)?), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let left = get_child_by_field_name::< + NodeTypes<'db>, + Expression<'db>, + >(context, &node, "left")?; + ids.push(left.clone()); + let right = get_child_by_field_name::< + NodeTypes<'db>, + Expression<'db>, + >(context, &node, "right")?; + ids.push(right.clone()); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + left, + right, + }, + ids, + )) + } +} +impl<'db> BinaryExpression<'db> { + const KIND_NAME: &'static str = "binary_expression"; + pub fn left(&self, tree: &'db Tree>) -> ExpressionRef<'db> { + tree.get(&self.left).unwrap().as_ref().try_into().unwrap() + } + pub fn right(&self, tree: &'db Tree>) -> ExpressionRef<'db> { + tree.get(&self.right).unwrap().as_ref().try_into().unwrap() } } impl<'db> CSTNode<'db> for BinaryExpression<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -133,66 +323,56 @@ impl<'db> CSTNode<'db> for BinaryExpression<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for BinaryExpression<'db1> { - type Child = BinaryExpressionChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = vec![]; - children - .push( - Self::Child::try_from(NodeTypes::from(self.left.as_ref().clone())) - .unwrap(), - ); - children - .push( - Self::Child::try_from(NodeTypes::from(self.right.as_ref().clone())) - .unwrap(), - ); +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for BinaryExpression<'db1> { + type Child<'db2> = BinaryExpressionChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = vec![]; + children.push(context.get(&self.left).unwrap().as_ref().try_into().unwrap()); + children.push(context.get(&self.right).unwrap().as_ref().try_into().unwrap()); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { "left" => { - vec![ - Self::Child::try_from(NodeTypes::from(self.left.as_ref().clone())) - .unwrap() - ] + vec![context.get(& self.left).unwrap().as_ref().try_into().unwrap()] } "right" => { - vec![ - Self::Child::try_from(NodeTypes::from(self.right.as_ref().clone())) - .unwrap() - ] + vec![context.get(& self.right).unwrap().as_ref().try_into().unwrap()] } _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { - 1u16 => { - vec![ - Self::Child::try_from(NodeTypes::from(self.left.as_ref().clone())) - .unwrap() - ] - } - 1u16 => { - vec![ - Self::Child::try_from(NodeTypes::from(self.right.as_ref().clone())) - .unwrap() - ] - } + 1u16 => vec![context.get(& self.left).unwrap().as_ref().try_into().unwrap()], + 1u16 => vec![context.get(& self.right).unwrap().as_ref().try_into().unwrap()], _ => vec![], } } @@ -202,54 +382,63 @@ impl<'db> std::hash::Hash for BinaryExpression<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for BinaryExpression<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for BinaryExpression<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct Literal<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for Literal<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for Literal<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> Literal<'db> { + const KIND_NAME: &'static str = "literal"; +} impl<'db> CSTNode<'db> for Literal<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -267,29 +456,43 @@ impl<'db> CSTNode<'db> for Literal<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for Literal<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for Literal<'db1> { + type Child<'db2> = Literal<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -300,16 +503,37 @@ impl<'db> std::hash::Hash for Literal<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for Literal<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for Literal<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +impl<'db> TreeNode for NodeTypes<'db> {} #[salsa::tracked] pub struct Parsed<'db> { + #[id] + id: FileNodeId<'db>, #[tracked] #[return_ref] - pub program: Option>, + #[no_clone] + pub tree: Tree>, + pub program: indextree::NodeId, } -pub fn parse_program_raw( - db: &dyn salsa::Database, +pub fn parse_program_raw<'db>( + db: &'db dyn salsa::Database, input: codegen_sdk_cst::Input, -) -> Option> { + path: PathBuf, +) -> Option> { let buffer = Bytes::from(input.content(db).as_bytes().to_vec()); let tree = codegen_sdk_common::language::language::Language .parse_tree_sitter(&input.content(db)); @@ -319,15 +543,20 @@ pub fn parse_program_raw( ParseError::SyntaxError.report(db); None } else { - let buffer = Arc::new(buffer); - Program::from_node(db, tree.root_node(), &buffer) + let mut context = ParseContext::new(db, path, buffer); + let root_id = Program::orphaned(&mut context, tree.root_node()) .map_or_else( |e| { e.report(db); None }, |program| { Some(program) }, - ) + ); + if let Some(program) = root_id { + Some(Parsed::new(db, context.file_id, context.tree, program)) + } else { + None + } } } Err(e) => { @@ -336,15 +565,21 @@ pub fn parse_program_raw( } } } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn parse_program( db: &dyn salsa::Database, input: codegen_sdk_cst::Input, ) -> Parsed<'_> { - Parsed::new(db, parse_program_raw(db, input)) + let raw = parse_program_raw(db, input, std::path::PathBuf::new()); + if let Some(parsed) = raw { + parsed + } else { + panic!("Failed to parse program"); + } } pub struct Language; impl CSTLanguage for Language { + type Types<'db> = NodeTypes<'db>; type Program<'db> = Program<'db>; fn language() -> &'static codegen_sdk_common::language::Language { &codegen_sdk_common::language::language::Language @@ -352,8 +587,12 @@ impl CSTLanguage for Language { fn parse<'db>( db: &'db dyn salsa::Database, content: std::string::String, - ) -> &'db Option> { + ) -> Option<(&'db Self::Program<'db>, &'db Tree>)> { let input = codegen_sdk_cst::Input::new(db, content); - return parse_program(db, input).program(db); + let parsed = parse_program(db, input); + let program = parsed.program(db); + let tree = parsed.tree(db); + let program = tree.get(&program).unwrap().as_ref(); + Some((program.try_into().unwrap(), tree)) } } diff --git a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_children__subtypes_with_children.snap b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_children__subtypes_with_children.snap index d970f6be..f57a9804 100644 --- a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_children__subtypes_with_children.snap +++ b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_children__subtypes_with_children.snap @@ -8,11 +8,14 @@ use codegen_sdk_common::*; use subenum::subenum; use std::backtrace::Backtrace; use bytes::Bytes; -use derive_generic_visitor::Drive; use ambassador::Delegate; +use derive_more::Debug; +use ambassador::delegate_to_methods; use codegen_sdk_cst::CSTLanguage; +use crate::cst::tree::ParseContext; +use std::path::PathBuf; #[subenum(BlockChildren, IfStatementChildren, Statement)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(IfStatementChildren)] @@ -37,15 +40,15 @@ impl<'db3> From> for NodeTypes<'db3> { Self::ReturnStatement(node) } } -impl<'db4> FromNode<'db4> for BlockChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for BlockChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok(Self::ReturnStatement(ReturnStatement::from_node(db, node, buffer)?)) + let (node, ids) = ReturnStatement::from_node(context, node)?; + Ok((Self::ReturnStatement(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -56,14 +59,16 @@ impl<'db4> FromNode<'db4> for BlockChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for IfStatementChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for IfStatementChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::Block(Block::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = Block::from_node(context, node)?; + Ok((Self::Block(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), @@ -73,15 +78,15 @@ impl<'db4> FromNode<'db4> for IfStatementChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for Statement<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Statement<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok(Self::ReturnStatement(ReturnStatement::from_node(db, node, buffer)?)) + let (node, ids) = ReturnStatement::from_node(context, node)?; + Ok((Self::ReturnStatement(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -92,56 +97,286 @@ impl<'db4> FromNode<'db4> for Statement<'db4> { } } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[subenum(BlockChildrenRef, IfStatementChildrenRef, StatementRef)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)] +pub enum NodeTypesRef<'db1> { + #[subenum(IfStatementChildrenRef)] + Block(&'db1 Block<'db1>), + #[subenum(StatementRef, BlockChildrenRef)] + IfStatement(&'db1 IfStatement<'db1>), + #[subenum(StatementRef, BlockChildrenRef)] + ReturnStatement(&'db1 ReturnStatement<'db1>), +} +impl<'db3> From<&'db3 Block<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Block<'db3>) -> Self { + Self::Block(node) + } +} +impl<'db3> From<&'db3 IfStatement<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 IfStatement<'db3>) -> Self { + Self::IfStatement(node) + } +} +impl<'db3> From<&'db3 ReturnStatement<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 ReturnStatement<'db3>) -> Self { + Self::ReturnStatement(node) + } +} +impl<'db3> NodeTypes<'db3> { + pub fn as_ref(&'db3 self) -> NodeTypesRef<'db3> { + match self { + Self::Block(data) => NodeTypesRef::Block(data), + Self::IfStatement(data) => NodeTypesRef::IfStatement(data), + Self::ReturnStatement(data) => NodeTypesRef::ReturnStatement(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> NodeTypesRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::Block(data) => *data, + Self::IfStatement(data) => *data, + Self::ReturnStatement(data) => *data, + } + } +} +impl<'db3> From<&'db3 NodeTypes<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 NodeTypes<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 Block<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::Block(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 IfStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::IfStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 ReturnStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::ReturnStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> BlockChildren<'db3> { + pub fn as_ref(&'db3 self) -> BlockChildrenRef<'db3> { + match self { + Self::IfStatement(data) => BlockChildrenRef::IfStatement(data), + Self::ReturnStatement(data) => BlockChildrenRef::ReturnStatement(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> BlockChildrenRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::IfStatement(data) => *data, + Self::ReturnStatement(data) => *data, + } + } +} +impl<'db3> From<&'db3 BlockChildren<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 BlockChildren<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 IfStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: BlockChildrenRef<'db3>) -> Result { + if let BlockChildrenRef::IfStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 ReturnStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: BlockChildrenRef<'db3>) -> Result { + if let BlockChildrenRef::ReturnStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> IfStatementChildren<'db3> { + pub fn as_ref(&'db3 self) -> IfStatementChildrenRef<'db3> { + match self { + Self::Block(data) => IfStatementChildrenRef::Block(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> IfStatementChildrenRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::Block(data) => *data, + } + } +} +impl<'db3> From<&'db3 IfStatementChildren<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 IfStatementChildren<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 Block<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: IfStatementChildrenRef<'db3>) -> Result { + if let IfStatementChildrenRef::Block(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> Statement<'db3> { + pub fn as_ref(&'db3 self) -> StatementRef<'db3> { + match self { + Self::IfStatement(data) => StatementRef::IfStatement(data), + Self::ReturnStatement(data) => StatementRef::ReturnStatement(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> StatementRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::IfStatement(data) => *data, + Self::ReturnStatement(data) => *data, + } + } +} +impl<'db3> From<&'db3 Statement<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Statement<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 IfStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: StatementRef<'db3>) -> Result { + if let StatementRef::IfStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 ReturnStatement<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: StatementRef<'db3>) -> Result { + if let StatementRef::ReturnStatement(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct Block<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub _children: Vec>, + pub _children: Vec, } -impl<'db> FromNode<'db> for Block<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for Block<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - _children: named_children_without_field_names(db, node, buffer)?, - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let _children = named_children_without_field_names::< + NodeTypes<'db>, + BlockChildren<'db>, + >(context, node)?; + for child in _children.iter().cloned() { + ids.push(child); + } + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + _children, + }, + ids, + )) } } +impl<'db> Block<'db> { + const KIND_NAME: &'static str = "block"; +} impl<'db> CSTNode<'db> for Block<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -159,31 +394,49 @@ impl<'db> CSTNode<'db> for Block<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for Block<'db1> { - type Child = BlockChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = self._children.iter().cloned().collect(); +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for Block<'db1> { + type Child<'db2> = BlockChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = self + ._children + .iter() + .map(|c| context.get(c).unwrap().as_ref().try_into().unwrap()) + .collect(); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -194,56 +447,72 @@ impl<'db> std::hash::Hash for Block<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for Block<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for Block<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct IfStatement<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub _children: Vec>, + pub _children: Vec, } -impl<'db> FromNode<'db> for IfStatement<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for IfStatement<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - _children: named_children_without_field_names(db, node, buffer)?, - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let _children = named_children_without_field_names::< + NodeTypes<'db>, + IfStatementChildren<'db>, + >(context, node)?; + for child in _children.iter().cloned() { + ids.push(child); + } + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + _children, + }, + ids, + )) } } +impl<'db> IfStatement<'db> { + const KIND_NAME: &'static str = "if_statement"; +} impl<'db> CSTNode<'db> for IfStatement<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -261,31 +530,49 @@ impl<'db> CSTNode<'db> for IfStatement<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for IfStatement<'db1> { - type Child = IfStatementChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = self._children.iter().cloned().collect(); +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for IfStatement<'db1> { + type Child<'db2> = IfStatementChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = self + ._children + .iter() + .map(|c| context.get(c).unwrap().as_ref().try_into().unwrap()) + .collect(); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -296,54 +583,63 @@ impl<'db> std::hash::Hash for IfStatement<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for IfStatement<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for IfStatement<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct ReturnStatement<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for ReturnStatement<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for ReturnStatement<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> ReturnStatement<'db> { + const KIND_NAME: &'static str = "return_statement"; +} impl<'db> CSTNode<'db> for ReturnStatement<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -361,29 +657,43 @@ impl<'db> CSTNode<'db> for ReturnStatement<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for ReturnStatement<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for ReturnStatement<'db1> { + type Child<'db2> = ReturnStatement<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -394,16 +704,37 @@ impl<'db> std::hash::Hash for ReturnStatement<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for ReturnStatement<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for ReturnStatement<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +impl<'db> TreeNode for NodeTypes<'db> {} #[salsa::tracked] pub struct Parsed<'db> { + #[id] + id: FileNodeId<'db>, #[tracked] #[return_ref] - pub program: Option>, + #[no_clone] + pub tree: Tree>, + pub program: indextree::NodeId, } -pub fn parse_program_raw( - db: &dyn salsa::Database, +pub fn parse_program_raw<'db>( + db: &'db dyn salsa::Database, input: codegen_sdk_cst::Input, -) -> Option> { + path: PathBuf, +) -> Option> { let buffer = Bytes::from(input.content(db).as_bytes().to_vec()); let tree = codegen_sdk_common::language::language::Language .parse_tree_sitter(&input.content(db)); @@ -413,15 +744,20 @@ pub fn parse_program_raw( ParseError::SyntaxError.report(db); None } else { - let buffer = Arc::new(buffer); - Program::from_node(db, tree.root_node(), &buffer) + let mut context = ParseContext::new(db, path, buffer); + let root_id = Program::orphaned(&mut context, tree.root_node()) .map_or_else( |e| { e.report(db); None }, |program| { Some(program) }, - ) + ); + if let Some(program) = root_id { + Some(Parsed::new(db, context.file_id, context.tree, program)) + } else { + None + } } } Err(e) => { @@ -430,15 +766,21 @@ pub fn parse_program_raw( } } } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn parse_program( db: &dyn salsa::Database, input: codegen_sdk_cst::Input, ) -> Parsed<'_> { - Parsed::new(db, parse_program_raw(db, input)) + let raw = parse_program_raw(db, input, std::path::PathBuf::new()); + if let Some(parsed) = raw { + parsed + } else { + panic!("Failed to parse program"); + } } pub struct Language; impl CSTLanguage for Language { + type Types<'db> = NodeTypes<'db>; type Program<'db> = Program<'db>; fn language() -> &'static codegen_sdk_common::language::Language { &codegen_sdk_common::language::language::Language @@ -446,8 +788,12 @@ impl CSTLanguage for Language { fn parse<'db>( db: &'db dyn salsa::Database, content: std::string::String, - ) -> &'db Option> { + ) -> Option<(&'db Self::Program<'db>, &'db Tree>)> { let input = codegen_sdk_cst::Input::new(db, content); - return parse_program(db, input).program(db); + let parsed = parse_program(db, input); + let program = parsed.program(db); + let tree = parsed.tree(db); + let program = tree.get(&program).unwrap().as_ref(); + Some((program.try_into().unwrap(), tree)) } } diff --git a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_multiple_inheritance__multiple_inheritance.snap b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_multiple_inheritance__multiple_inheritance.snap index 37173890..e7e00f03 100644 --- a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_multiple_inheritance__multiple_inheritance.snap +++ b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_multiple_inheritance__multiple_inheritance.snap @@ -8,11 +8,14 @@ use codegen_sdk_common::*; use subenum::subenum; use std::backtrace::Backtrace; use bytes::Bytes; -use derive_generic_visitor::Drive; use ambassador::Delegate; +use derive_more::Debug; +use ambassador::delegate_to_methods; use codegen_sdk_cst::CSTLanguage; +use crate::cst::tree::ParseContext; +use std::path::PathBuf; #[subenum(ClassMember, Declaration)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(Declaration, ClassMember)] @@ -23,14 +26,16 @@ impl<'db3> From> for NodeTypes<'db3> { Self::ClassMethod(node) } } -impl<'db4> FromNode<'db4> for ClassMember<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for ClassMember<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::ClassMethod(ClassMethod::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = ClassMethod::from_node(context, node)?; + Ok((Self::ClassMethod(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), @@ -40,14 +45,16 @@ impl<'db4> FromNode<'db4> for ClassMember<'db4> { } } } -impl<'db4> FromNode<'db4> for Declaration<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Declaration<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { - 0u16 => Ok(Self::ClassMethod(ClassMethod::from_node(db, node, buffer)?)), + 0u16 => { + let (node, ids) = ClassMethod::from_node(context, node)?; + Ok((Self::ClassMethod(node), ids)) + } _ => { Err(ParseError::UnexpectedNode { node_type: node.kind().to_string(), @@ -57,54 +64,164 @@ impl<'db4> FromNode<'db4> for Declaration<'db4> { } } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[subenum(ClassMemberRef, DeclarationRef)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)] +pub enum NodeTypesRef<'db1> { + #[subenum(DeclarationRef, ClassMemberRef)] + ClassMethod(&'db1 ClassMethod<'db1>), +} +impl<'db3> From<&'db3 ClassMethod<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 ClassMethod<'db3>) -> Self { + Self::ClassMethod(node) + } +} +impl<'db3> NodeTypes<'db3> { + pub fn as_ref(&'db3 self) -> NodeTypesRef<'db3> { + match self { + Self::ClassMethod(data) => NodeTypesRef::ClassMethod(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> NodeTypesRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::ClassMethod(data) => *data, + } + } +} +impl<'db3> From<&'db3 NodeTypes<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 NodeTypes<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 ClassMethod<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::ClassMethod(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> ClassMember<'db3> { + pub fn as_ref(&'db3 self) -> ClassMemberRef<'db3> { + match self { + Self::ClassMethod(data) => ClassMemberRef::ClassMethod(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> ClassMemberRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::ClassMethod(data) => *data, + } + } +} +impl<'db3> From<&'db3 ClassMember<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 ClassMember<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 ClassMethod<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: ClassMemberRef<'db3>) -> Result { + if let ClassMemberRef::ClassMethod(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> Declaration<'db3> { + pub fn as_ref(&'db3 self) -> DeclarationRef<'db3> { + match self { + Self::ClassMethod(data) => DeclarationRef::ClassMethod(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> DeclarationRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::ClassMethod(data) => *data, + } + } +} +impl<'db3> From<&'db3 Declaration<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Declaration<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 ClassMethod<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: DeclarationRef<'db3>) -> Result { + if let DeclarationRef::ClassMethod(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct ClassMethod<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, } -impl<'db> FromNode<'db> for ClassMethod<'db> { +impl<'db> FromNode<'db, NodeTypes<'db>> for ClassMethod<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + }, + ids, + )) } } +impl<'db> ClassMethod<'db> { + const KIND_NAME: &'static str = "class_method"; +} impl<'db> CSTNode<'db> for ClassMethod<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -122,29 +239,43 @@ impl<'db> CSTNode<'db> for ClassMethod<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for ClassMethod<'db1> { - type Child = Self; - fn children(&self) -> Vec { +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for ClassMethod<'db1> { + type Child<'db2> = ClassMethod<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { vec![] } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { _ => vec![], } @@ -155,16 +286,37 @@ impl<'db> std::hash::Hash for ClassMethod<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for ClassMethod<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for ClassMethod<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +impl<'db> TreeNode for NodeTypes<'db> {} #[salsa::tracked] pub struct Parsed<'db> { + #[id] + id: FileNodeId<'db>, #[tracked] #[return_ref] - pub program: Option>, + #[no_clone] + pub tree: Tree>, + pub program: indextree::NodeId, } -pub fn parse_program_raw( - db: &dyn salsa::Database, +pub fn parse_program_raw<'db>( + db: &'db dyn salsa::Database, input: codegen_sdk_cst::Input, -) -> Option> { + path: PathBuf, +) -> Option> { let buffer = Bytes::from(input.content(db).as_bytes().to_vec()); let tree = codegen_sdk_common::language::language::Language .parse_tree_sitter(&input.content(db)); @@ -174,15 +326,20 @@ pub fn parse_program_raw( ParseError::SyntaxError.report(db); None } else { - let buffer = Arc::new(buffer); - Program::from_node(db, tree.root_node(), &buffer) + let mut context = ParseContext::new(db, path, buffer); + let root_id = Program::orphaned(&mut context, tree.root_node()) .map_or_else( |e| { e.report(db); None }, |program| { Some(program) }, - ) + ); + if let Some(program) = root_id { + Some(Parsed::new(db, context.file_id, context.tree, program)) + } else { + None + } } } Err(e) => { @@ -191,15 +348,21 @@ pub fn parse_program_raw( } } } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn parse_program( db: &dyn salsa::Database, input: codegen_sdk_cst::Input, ) -> Parsed<'_> { - Parsed::new(db, parse_program_raw(db, input)) + let raw = parse_program_raw(db, input, std::path::PathBuf::new()); + if let Some(parsed) = raw { + parsed + } else { + panic!("Failed to parse program"); + } } pub struct Language; impl CSTLanguage for Language { + type Types<'db> = NodeTypes<'db>; type Program<'db> = Program<'db>; fn language() -> &'static codegen_sdk_common::language::Language { &codegen_sdk_common::language::language::Language @@ -207,8 +370,12 @@ impl CSTLanguage for Language { fn parse<'db>( db: &'db dyn salsa::Database, content: std::string::String, - ) -> &'db Option> { + ) -> Option<(&'db Self::Program<'db>, &'db Tree>)> { let input = codegen_sdk_cst::Input::new(db, content); - return parse_program(db, input).program(db); + let parsed = parse_program(db, input); + let program = parsed.program(db); + let tree = parsed.tree(db); + let program = tree.get(&program).unwrap().as_ref(); + Some((program.try_into().unwrap(), tree)) } } diff --git a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_recursive__recursive_subtypes.snap b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_recursive__recursive_subtypes.snap index 78afa809..5a68711b 100644 --- a/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_recursive__recursive_subtypes.snap +++ b/codegen-sdk-cst-generator/src/tests/snapshots/codegen_sdk_cst_generator__tests__test_subtypes_recursive__recursive_subtypes.snap @@ -8,11 +8,14 @@ use codegen_sdk_common::*; use subenum::subenum; use std::backtrace::Backtrace; use bytes::Bytes; -use derive_generic_visitor::Drive; use ambassador::Delegate; +use derive_more::Debug; +use ambassador::delegate_to_methods; use codegen_sdk_cst::CSTLanguage; +use crate::cst::tree::ParseContext; +use std::path::PathBuf; #[subenum(BinaryExpressionChildren, CallExpressionChildren, Expression)] -#[derive(Debug, Clone, Eq, PartialEq, Drive, Hash, salsa::Update, Delegate)] +#[derive(Debug, Eq, PartialEq, Clone, Hash, salsa::Update, Delegate, Ord, PartialOrd)] #[delegate(CSTNode<'db1>)] pub enum NodeTypes<'db1> { #[subenum(Expression, BinaryExpressionChildren, CallExpressionChildren)] @@ -30,15 +33,15 @@ impl<'db3> From> for NodeTypes<'db3> { Self::CallExpression(node) } } -impl<'db4> FromNode<'db4> for BinaryExpressionChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for BinaryExpressionChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok(Self::CallExpression(CallExpression::from_node(db, node, buffer)?)) + let (node, ids) = CallExpression::from_node(context, node)?; + Ok((Self::CallExpression(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -49,15 +52,15 @@ impl<'db4> FromNode<'db4> for BinaryExpressionChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for CallExpressionChildren<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for CallExpressionChildren<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok(Self::CallExpression(CallExpression::from_node(db, node, buffer)?)) + let (node, ids) = CallExpression::from_node(context, node)?; + Ok((Self::CallExpression(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -68,15 +71,15 @@ impl<'db4> FromNode<'db4> for CallExpressionChildren<'db4> { } } } -impl<'db4> FromNode<'db4> for Expression<'db4> { +impl<'db4> FromNode<'db4, NodeTypes<'db4>> for Expression<'db4> { fn from_node( - db: &'db4 dyn salsa::Database, + context: &mut ParseContext<'db4, NodeTypes<'db4>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { + ) -> Result<(Self, Vec), ParseError> { match node.kind_id() { 0u16 => { - Ok(Self::CallExpression(CallExpression::from_node(db, node, buffer)?)) + let (node, ids) = CallExpression::from_node(context, node)?; + Ok((Self::CallExpression(node), ids)) } _ => { Err(ParseError::UnexpectedNode { @@ -87,58 +90,296 @@ impl<'db4> FromNode<'db4> for Expression<'db4> { } } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +#[subenum(BinaryExpressionChildrenRef, CallExpressionChildrenRef, ExpressionRef)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)] +pub enum NodeTypesRef<'db1> { + #[subenum(ExpressionRef, BinaryExpressionChildrenRef, CallExpressionChildrenRef)] + BinaryExpression(&'db1 BinaryExpression<'db1>), + #[subenum(ExpressionRef, BinaryExpressionChildrenRef, CallExpressionChildrenRef)] + CallExpression(&'db1 CallExpression<'db1>), +} +impl<'db3> From<&'db3 BinaryExpression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 BinaryExpression<'db3>) -> Self { + Self::BinaryExpression(node) + } +} +impl<'db3> From<&'db3 CallExpression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 CallExpression<'db3>) -> Self { + Self::CallExpression(node) + } +} +impl<'db3> NodeTypes<'db3> { + pub fn as_ref(&'db3 self) -> NodeTypesRef<'db3> { + match self { + Self::BinaryExpression(data) => NodeTypesRef::BinaryExpression(data), + Self::CallExpression(data) => NodeTypesRef::CallExpression(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> NodeTypesRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::CallExpression(data) => *data, + } + } +} +impl<'db3> From<&'db3 NodeTypes<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 NodeTypes<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 CallExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: NodeTypesRef<'db3>) -> Result { + if let NodeTypesRef::CallExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> BinaryExpressionChildren<'db3> { + pub fn as_ref(&'db3 self) -> BinaryExpressionChildrenRef<'db3> { + match self { + Self::BinaryExpression(data) => { + BinaryExpressionChildrenRef::BinaryExpression(data) + } + Self::CallExpression(data) => { + BinaryExpressionChildrenRef::CallExpression(data) + } + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> BinaryExpressionChildrenRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::CallExpression(data) => *data, + } + } +} +impl<'db3> From<&'db3 BinaryExpressionChildren<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 BinaryExpressionChildren<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: BinaryExpressionChildrenRef<'db3>) -> Result { + if let BinaryExpressionChildrenRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 CallExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: BinaryExpressionChildrenRef<'db3>) -> Result { + if let BinaryExpressionChildrenRef::CallExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> CallExpressionChildren<'db3> { + pub fn as_ref(&'db3 self) -> CallExpressionChildrenRef<'db3> { + match self { + Self::BinaryExpression(data) => { + CallExpressionChildrenRef::BinaryExpression(data) + } + Self::CallExpression(data) => CallExpressionChildrenRef::CallExpression(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> CallExpressionChildrenRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::CallExpression(data) => *data, + } + } +} +impl<'db3> From<&'db3 CallExpressionChildren<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 CallExpressionChildren<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: CallExpressionChildrenRef<'db3>) -> Result { + if let CallExpressionChildrenRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 CallExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: CallExpressionChildrenRef<'db3>) -> Result { + if let CallExpressionChildrenRef::CallExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> Expression<'db3> { + pub fn as_ref(&'db3 self) -> ExpressionRef<'db3> { + match self { + Self::BinaryExpression(data) => ExpressionRef::BinaryExpression(data), + Self::CallExpression(data) => ExpressionRef::CallExpression(data), + } + } +} +#[delegate_to_methods] +#[delegate(CSTNode<'db3>, target_ref = "deref")] +impl<'db3> ExpressionRef<'db3> { + fn deref<'db2>(&'db2 self) -> &'db2 dyn CSTNode<'db3> { + match self { + Self::BinaryExpression(data) => *data, + Self::CallExpression(data) => *data, + } + } +} +impl<'db3> From<&'db3 Expression<'db3>> for NodeTypesRef<'db3> { + fn from(node: &'db3 Expression<'db3>) -> Self { + node.as_ref().into() + } +} +impl<'db3> TryFrom> for &'db3 BinaryExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: ExpressionRef<'db3>) -> Result { + if let ExpressionRef::BinaryExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +impl<'db3> TryFrom> for &'db3 CallExpression<'db3> { + type Error = codegen_sdk_cst::ConversionError; + fn try_from(node: ExpressionRef<'db3>) -> Result { + if let ExpressionRef::CallExpression(node) = node { + Ok(node) + } else { + Err(codegen_sdk_cst::ConversionError { + expected: "TODO".to_string(), + actual: node.kind_name().to_string(), + backtrace: Backtrace::capture(), + }) + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct BinaryExpression<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub left: Box>, - pub right: Box>, -} -impl<'db> FromNode<'db> for BinaryExpression<'db> { + pub left: indextree::NodeId, + pub right: indextree::NodeId, +} +impl<'db> FromNode<'db, NodeTypes<'db>> for BinaryExpression<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - left: Box::new(get_child_by_field_name(db, &node, "left", buffer)?), - right: Box::new(get_child_by_field_name(db, &node, "right", buffer)?), - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let left = get_child_by_field_name::< + NodeTypes<'db>, + Expression<'db>, + >(context, &node, "left")?; + ids.push(left.clone()); + let right = get_child_by_field_name::< + NodeTypes<'db>, + Expression<'db>, + >(context, &node, "right")?; + ids.push(right.clone()); + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + left, + right, + }, + ids, + )) + } +} +impl<'db> BinaryExpression<'db> { + const KIND_NAME: &'static str = "binary_expression"; + pub fn left(&self, tree: &'db Tree>) -> ExpressionRef<'db> { + tree.get(&self.left).unwrap().as_ref().try_into().unwrap() + } + pub fn right(&self, tree: &'db Tree>) -> ExpressionRef<'db> { + tree.get(&self.right).unwrap().as_ref().try_into().unwrap() } } impl<'db> CSTNode<'db> for BinaryExpression<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -156,66 +397,56 @@ impl<'db> CSTNode<'db> for BinaryExpression<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for BinaryExpression<'db1> { - type Child = BinaryExpressionChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = vec![]; - children - .push( - Self::Child::try_from(NodeTypes::from(self.left.as_ref().clone())) - .unwrap(), - ); - children - .push( - Self::Child::try_from(NodeTypes::from(self.right.as_ref().clone())) - .unwrap(), - ); +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for BinaryExpression<'db1> { + type Child<'db2> = BinaryExpressionChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = vec![]; + children.push(context.get(&self.left).unwrap().as_ref().try_into().unwrap()); + children.push(context.get(&self.right).unwrap().as_ref().try_into().unwrap()); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { "left" => { - vec![ - Self::Child::try_from(NodeTypes::from(self.left.as_ref().clone())) - .unwrap() - ] + vec![context.get(& self.left).unwrap().as_ref().try_into().unwrap()] } "right" => { - vec![ - Self::Child::try_from(NodeTypes::from(self.right.as_ref().clone())) - .unwrap() - ] + vec![context.get(& self.right).unwrap().as_ref().try_into().unwrap()] } _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { - 1u16 => { - vec![ - Self::Child::try_from(NodeTypes::from(self.left.as_ref().clone())) - .unwrap() - ] - } - 1u16 => { - vec![ - Self::Child::try_from(NodeTypes::from(self.right.as_ref().clone())) - .unwrap() - ] - } + 1u16 => vec![context.get(& self.left).unwrap().as_ref().try_into().unwrap()], + 1u16 => vec![context.get(& self.right).unwrap().as_ref().try_into().unwrap()], _ => vec![], } } @@ -225,58 +456,82 @@ impl<'db> std::hash::Hash for BinaryExpression<'db> { self.id.hash(state); } } -#[derive(Debug, Clone, Drive, Eq, PartialEq, salsa::Update)] +impl<'db> PartialOrd for BinaryExpression<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for BinaryExpression<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +#[derive(Debug, Eq, PartialEq, Clone, salsa::Update)] pub struct CallExpression<'db> { - #[drive(skip)] + id: CSTNodeId<'db>, + file_id: FileNodeId<'db>, start_byte: usize, - #[drive(skip)] end_byte: usize, - #[drive(skip)] - _kind: std::string::String, - #[drive(skip)] start_position: Point<'db>, - #[drive(skip)] end_position: Point<'db>, - #[drive(skip)] + #[debug(ignore)] buffer: Arc, - #[drive(skip)] - kind_id: u16, - #[drive(skip)] is_error: bool, - #[drive(skip)] - named: bool, - #[drive(skip)] - id: usize, - pub _children: Vec>, - pub callee: Box>, -} -impl<'db> FromNode<'db> for CallExpression<'db> { + pub _children: Vec, + pub callee: indextree::NodeId, +} +impl<'db> FromNode<'db, NodeTypes<'db>> for CallExpression<'db> { fn from_node( - db: &'db dyn salsa::Database, + context: &mut ParseContext<'db, NodeTypes<'db>>, node: tree_sitter::Node, - buffer: &Arc, - ) -> Result { - let start_position = Point::from(db, node.start_position()); - let end_position = Point::from(db, node.end_position()); - Ok(Self { - start_byte: node.start_byte(), - end_byte: node.end_byte(), - _kind: node.kind().to_string(), - start_position: start_position, - end_position: end_position, - buffer: buffer.clone(), - kind_id: node.kind_id(), - is_error: node.is_error(), - named: node.is_named(), - id: node.id(), - callee: Box::new(get_child_by_field_name(db, &node, "callee", buffer)?), - _children: named_children_without_field_names(db, node, buffer)?, - }) + ) -> Result<(Self, Vec), ParseError> { + let start_position = Point::from(context.db, node.start_position()); + let end_position = Point::from(context.db, node.end_position()); + let id = CSTNodeId::new(context.db, context.file_id, node.id()); + let mut ids = Vec::new(); + let callee = get_child_by_field_name::< + NodeTypes<'db>, + Expression<'db>, + >(context, &node, "callee")?; + ids.push(callee.clone()); + let _children = named_children_without_field_names::< + NodeTypes<'db>, + CallExpressionChildren<'db>, + >(context, node)?; + for child in _children.iter().cloned() { + ids.push(child); + } + Ok(( + Self { + start_byte: node.start_byte(), + end_byte: node.end_byte(), + start_position: start_position, + end_position: end_position, + buffer: context.buffer.clone(), + is_error: node.is_error(), + id, + file_id: context.file_id.clone(), + callee, + _children, + }, + ids, + )) + } +} +impl<'db> CallExpression<'db> { + const KIND_NAME: &'static str = "call_expression"; + pub fn callee(&self, tree: &'db Tree>) -> ExpressionRef<'db> { + tree.get(&self.callee).unwrap().as_ref().try_into().unwrap() } } impl<'db> CSTNode<'db> for CallExpression<'db> { - fn kind(&self) -> &str { - &self._kind + fn kind_name(&self) -> &str { + &Self::KIND_NAME } fn start_byte(&self) -> usize { self.start_byte @@ -294,48 +549,56 @@ impl<'db> CSTNode<'db> for CallExpression<'db> { &self.buffer } fn kind_id(&self) -> u16 { - self.kind_id + 0u16 } fn is_error(&self) -> bool { self.is_error } fn is_named(&self) -> bool { - self.named + true } - fn id(&self) -> usize { + fn id(&self) -> CSTNodeId<'db> { self.id } + fn file_id(&self) -> FileNodeId<'db> { + self.file_id + } } -impl<'db1> HasChildren<'db1> for CallExpression<'db1> { - type Child = CallExpressionChildren<'db1>; - fn children(&self) -> Vec { - let mut children: Vec<_> = self._children.iter().cloned().collect(); - children - .push( - Self::Child::try_from(NodeTypes::from(self.callee.as_ref().clone())) - .unwrap(), - ); +impl<'db1> HasChildren<'db1, NodeTypes<'db1>> for CallExpression<'db1> { + type Child<'db2> = CallExpressionChildrenRef<'db2> where Self: 'db2; + fn children<'db2>( + &'db2 self, + context: &'db2 Tree>, + ) -> Vec> { + let mut children: Vec> = self + ._children + .iter() + .map(|c| context.get(c).unwrap().as_ref().try_into().unwrap()) + .collect(); + children.push(context.get(&self.callee).unwrap().as_ref().try_into().unwrap()); children.sort_by_key(|c| c.start_byte()); children } - fn children_by_field_name(&self, field_name: &str) -> Vec { + fn children_by_field_name<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_name: &str, + ) -> Vec> { match field_name { "callee" => { - vec![ - Self::Child::try_from(NodeTypes::from(self.callee.as_ref().clone())) - .unwrap() - ] + vec![context.get(& self.callee).unwrap().as_ref().try_into().unwrap()] } _ => vec![], } } - fn children_by_field_id(&self, field_id: u16) -> Vec { + fn children_by_field_id<'db2>( + &'db2 self, + context: &'db2 Tree>, + field_id: u16, + ) -> Vec> { match field_id { 1u16 => { - vec![ - Self::Child::try_from(NodeTypes::from(self.callee.as_ref().clone())) - .unwrap() - ] + vec![context.get(& self.callee).unwrap().as_ref().try_into().unwrap()] } _ => vec![], } @@ -346,16 +609,37 @@ impl<'db> std::hash::Hash for CallExpression<'db> { self.id.hash(state); } } +impl<'db> PartialOrd for CallExpression<'db> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl<'db> Ord for CallExpression<'db> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let res = self.start_byte().cmp(&other.start_byte()); + if res == std::cmp::Ordering::Equal { + self.end_byte().cmp(&other.end_byte()) + } else { + res + } + } +} +impl<'db> TreeNode for NodeTypes<'db> {} #[salsa::tracked] pub struct Parsed<'db> { + #[id] + id: FileNodeId<'db>, #[tracked] #[return_ref] - pub program: Option>, + #[no_clone] + pub tree: Tree>, + pub program: indextree::NodeId, } -pub fn parse_program_raw( - db: &dyn salsa::Database, +pub fn parse_program_raw<'db>( + db: &'db dyn salsa::Database, input: codegen_sdk_cst::Input, -) -> Option> { + path: PathBuf, +) -> Option> { let buffer = Bytes::from(input.content(db).as_bytes().to_vec()); let tree = codegen_sdk_common::language::language::Language .parse_tree_sitter(&input.content(db)); @@ -365,15 +649,20 @@ pub fn parse_program_raw( ParseError::SyntaxError.report(db); None } else { - let buffer = Arc::new(buffer); - Program::from_node(db, tree.root_node(), &buffer) + let mut context = ParseContext::new(db, path, buffer); + let root_id = Program::orphaned(&mut context, tree.root_node()) .map_or_else( |e| { e.report(db); None }, |program| { Some(program) }, - ) + ); + if let Some(program) = root_id { + Some(Parsed::new(db, context.file_id, context.tree, program)) + } else { + None + } } } Err(e) => { @@ -382,15 +671,21 @@ pub fn parse_program_raw( } } } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn parse_program( db: &dyn salsa::Database, input: codegen_sdk_cst::Input, ) -> Parsed<'_> { - Parsed::new(db, parse_program_raw(db, input)) + let raw = parse_program_raw(db, input, std::path::PathBuf::new()); + if let Some(parsed) = raw { + parsed + } else { + panic!("Failed to parse program"); + } } pub struct Language; impl CSTLanguage for Language { + type Types<'db> = NodeTypes<'db>; type Program<'db> = Program<'db>; fn language() -> &'static codegen_sdk_common::language::Language { &codegen_sdk_common::language::language::Language @@ -398,8 +693,12 @@ impl CSTLanguage for Language { fn parse<'db>( db: &'db dyn salsa::Database, content: std::string::String, - ) -> &'db Option> { + ) -> Option<(&'db Self::Program<'db>, &'db Tree>)> { let input = codegen_sdk_cst::Input::new(db, content); - return parse_program(db, input).program(db); + let parsed = parse_program(db, input); + let program = parsed.program(db); + let tree = parsed.tree(db); + let program = tree.get(&program).unwrap().as_ref(); + Some((program.try_into().unwrap(), tree)) } } diff --git a/codegen-sdk-cst/Cargo.toml b/codegen-sdk-cst/Cargo.toml index 78b1ea56..d9d952b9 100644 --- a/codegen-sdk-cst/Cargo.toml +++ b/codegen-sdk-cst/Cargo.toml @@ -12,6 +12,7 @@ rkyv = { workspace = true } log = { workspace = true } salsa = { workspace = true } dashmap = "6.1.0" +thiserror = {workspace = true} [dev-dependencies] tempfile = { workspace = true } test-log = { workspace = true } diff --git a/codegen-sdk-cst/src/errors.rs b/codegen-sdk-cst/src/errors.rs new file mode 100644 index 00000000..1f7df8ed --- /dev/null +++ b/codegen-sdk-cst/src/errors.rs @@ -0,0 +1,11 @@ +use std::backtrace::Backtrace; + +use thiserror::Error; + +#[derive(Debug, Error)] +#[error("Conversion error: {expected} (expected) != {actual} (actual)")] +pub struct ConversionError { + pub expected: String, + pub actual: String, + pub backtrace: Backtrace, +} diff --git a/codegen-sdk-cst/src/language.rs b/codegen-sdk-cst/src/language.rs index 3a9d8718..8fe82c04 100644 --- a/codegen-sdk-cst/src/language.rs +++ b/codegen-sdk-cst/src/language.rs @@ -1,22 +1,26 @@ -use std::{path::PathBuf, sync::Arc}; +use std::{hash::Hash, path::PathBuf, sync::Arc}; use bytes::Bytes; use codegen_sdk_common::{ - ParseError, + ParseError, Tree, language::Language, traits::{CSTNode, FromNode}, + tree::TreeNode, }; pub trait CSTLanguage { - type Program<'db1>: CSTNode<'db1> + FromNode<'db1> + Send; + type Types<'db>: TreeNode; + type Program<'db1>: CSTNode<'db1> + FromNode<'db1, Self::Types<'db1>> + Send; fn language() -> &'static Language; - fn parse<'db>(db: &'db dyn salsa::Database, content: String) - -> &'db Option>; + fn parse<'db>( + db: &'db dyn salsa::Database, + content: String, + ) -> Option<(&'db Self::Program<'db>, &'db Tree>)>; fn parse_file_from_cache<'db>( db: &'db dyn salsa::Database, file_path: &PathBuf, #[cfg(feature = "serialization")] cache: &'db codegen_sdk_common::serialize::Cache, - ) -> Result<&'db Option>, ParseError> { + ) -> Result, &'db Tree>)>, ParseError> { #[cfg(feature = "serialization")] { let serialized_path = cache.get_path(file_path); @@ -25,24 +29,24 @@ pub trait CSTLanguage { return Ok(Some(parsed)); } } - Ok(&None) + Ok(None) } fn parse_file<'db>( db: &'db dyn salsa::Database, file_path: &PathBuf, #[cfg(feature = "serialization")] cache: &'db codegen_sdk_common::serialize::Cache, - ) -> Result<&'db Self::Program<'db>, ParseError> { + ) -> Result, &'db Tree>)>, ParseError> { if let Some(parsed) = Self::parse_file_from_cache( db, file_path, #[cfg(feature = "serialization")] cache, )? { - return Ok(parsed); + return Ok(Some(parsed)); } let content = std::fs::read_to_string(file_path)?; if let Some(parsed) = Self::parse(db, content) { - return Ok(parsed); + return Ok(Some(parsed)); } Err(ParseError::SyntaxError) } diff --git a/codegen-sdk-cst/src/lib.rs b/codegen-sdk-cst/src/lib.rs index f1c03665..700938dc 100644 --- a/codegen-sdk-cst/src/lib.rs +++ b/codegen-sdk-cst/src/lib.rs @@ -1,8 +1,10 @@ #![recursion_limit = "512"] -#![feature(trivial_bounds, extend_one)] +#![feature(trivial_bounds, extend_one, error_generic_member_access)] #![allow(unused)] - +mod errors; use std::{any::Any, path::PathBuf}; + +pub use errors::*; mod input; use dashmap::{DashMap, mapref::entry::Entry}; mod database; diff --git a/codegen-sdk-macros/src/lib.rs b/codegen-sdk-macros/src/lib.rs index 57b92503..cb168d40 100644 --- a/codegen-sdk-macros/src/lib.rs +++ b/codegen-sdk-macros/src/lib.rs @@ -104,7 +104,7 @@ pub fn parse_language(_item: TokenStream) -> TokenStream { let parsed = #package_name::ast::parse(db, file); return Parsed::new( db, - file.path(db), + FileNodeId::new(db, file.path(db)), Some(ParsedFile::#struct_name(parsed)), ); } diff --git a/codegen-sdk-resolution/src/references.rs b/codegen-sdk-resolution/src/references.rs index 81db74d6..5ee20621 100644 --- a/codegen-sdk-resolution/src/references.rs +++ b/codegen-sdk-resolution/src/references.rs @@ -4,7 +4,7 @@ pub trait References< 'db, ReferenceType: ResolveType<'db, Scope, Type = Self> + Clone, // References must resolve to this type Scope: crate::Scope<'db, Type = Self, ReferenceType = ReferenceType> + Clone, ->: Eq + PartialEq +>: Eq + PartialEq where Self:'db { fn references + Clone + 'db, T>(&self, codebase: &'db T, scope: &Scope) -> Vec where @@ -16,12 +16,12 @@ pub trait References< } fn references_for_scopes(&self, db: &'db dyn salsa::Database, scopes: Vec, scope: &Scope) -> Vec where - Self: Sized, + Self: Sized + 'db, { let mut results = Vec::new(); for reference in scope.clone().resolvables(db) { let resolved = reference.clone().resolve_type(db, scope.clone(), scopes.clone()); - if resolved.iter().any(|result| result == self) { + if resolved.iter().any(|result| *result == *self) { results.push(reference); } } diff --git a/codegen-sdk-resolution/src/resolve_type.rs b/codegen-sdk-resolution/src/resolve_type.rs index 72a134a6..62d6a85a 100644 --- a/codegen-sdk-resolution/src/resolve_type.rs +++ b/codegen-sdk-resolution/src/resolve_type.rs @@ -8,5 +8,5 @@ pub trait ResolveType<'db, T: Scope<'db>> { db: &'db dyn salsa::Database, scope: T, scopes: Vec, - ) -> Vec; + ) -> &'db Vec; } diff --git a/codegen-sdk-resolution/src/scope.rs b/codegen-sdk-resolution/src/scope.rs index b98dd09f..ec7baa9d 100644 --- a/codegen-sdk-resolution/src/scope.rs +++ b/codegen-sdk-resolution/src/scope.rs @@ -4,7 +4,7 @@ use crate::ResolveType; pub trait Scope<'db>: Sized { type Type; type ReferenceType: ResolveType<'db, Self, Type = Self::Type>; - fn resolve(self, db: &'db dyn salsa::Database, name: String) -> Vec; + fn resolve(self, db: &'db dyn salsa::Database, name: String) -> &'db Vec; /// Get all the resolvables (IE: function_calls) in the scope fn resolvables(self, db: &'db dyn salsa::Database) -> Vec; } diff --git a/languages/codegen-sdk-go/Cargo.toml b/languages/codegen-sdk-go/Cargo.toml index 2c4f0c17..0d8c919c 100644 --- a/languages/codegen-sdk-go/Cargo.toml +++ b/languages/codegen-sdk-go/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-java/Cargo.toml b/languages/codegen-sdk-java/Cargo.toml index 0d7e131c..b49e8677 100644 --- a/languages/codegen-sdk-java/Cargo.toml +++ b/languages/codegen-sdk-java/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-java/src/lib.rs b/languages/codegen-sdk-java/src/lib.rs index 188d6160..595ab58d 100644 --- a/languages/codegen-sdk-java/src/lib.rs +++ b/languages/codegen-sdk-java/src/lib.rs @@ -1,5 +1,5 @@ #![recursion_limit = "2048"] -#![allow(unused)] +#![allow(unused, irrefutable_let_patterns)] #![allow(non_snake_case)] pub mod cst { include!(concat!(env!("OUT_DIR"), "/java.rs")); diff --git a/languages/codegen-sdk-javascript/Cargo.toml b/languages/codegen-sdk-javascript/Cargo.toml index cbed7010..9b96f6ac 100644 --- a/languages/codegen-sdk-javascript/Cargo.toml +++ b/languages/codegen-sdk-javascript/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-json/Cargo.toml b/languages/codegen-sdk-json/Cargo.toml index 947df056..f2bb9761 100644 --- a/languages/codegen-sdk-json/Cargo.toml +++ b/languages/codegen-sdk-json/Cargo.toml @@ -9,7 +9,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-json/src/lib.rs b/languages/codegen-sdk-json/src/lib.rs index 23e5a92b..81485e68 100644 --- a/languages/codegen-sdk-json/src/lib.rs +++ b/languages/codegen-sdk-json/src/lib.rs @@ -1,4 +1,4 @@ -#![allow(unused)] +#![allow(unused, irrefutable_let_patterns)] pub mod cst { include!(concat!(env!("OUT_DIR"), "/json.rs")); } @@ -19,9 +19,8 @@ mod tests { } "; let db = codegen_sdk_cst::CSTDatabase::default(); - let module = crate::cst::JSON::parse(&db, content.to_string()) - .as_ref() - .unwrap(); - assert!(module.children().len() > 0); + let module = crate::cst::JSON::parse(&db, content.to_string()).unwrap(); + let (root, tree) = module; + assert!(root.children(tree).len() > 0); } } diff --git a/languages/codegen-sdk-jsx/Cargo.toml b/languages/codegen-sdk-jsx/Cargo.toml index 64ab9c95..bd203ae2 100644 --- a/languages/codegen-sdk-jsx/Cargo.toml +++ b/languages/codegen-sdk-jsx/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-markdown/Cargo.toml b/languages/codegen-sdk-markdown/Cargo.toml index 06e9af1e..420a66c9 100644 --- a/languages/codegen-sdk-markdown/Cargo.toml +++ b/languages/codegen-sdk-markdown/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-markdown/src/lib.rs b/languages/codegen-sdk-markdown/src/lib.rs index b2f144a0..eaec9d1b 100644 --- a/languages/codegen-sdk-markdown/src/lib.rs +++ b/languages/codegen-sdk-markdown/src/lib.rs @@ -1,5 +1,5 @@ #![recursion_limit = "2048"] -#![allow(unused)] +#![allow(unused, irrefutable_let_patterns)] pub mod cst { include!(concat!(env!("OUT_DIR"), "/markdown.rs")); } diff --git a/languages/codegen-sdk-python/Cargo.toml b/languages/codegen-sdk-python/Cargo.toml index 37e4eef5..b14c6976 100644 --- a/languages/codegen-sdk-python/Cargo.toml +++ b/languages/codegen-sdk-python/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-python/src/lib.rs b/languages/codegen-sdk-python/src/lib.rs index bfdaf008..5e3dfba4 100644 --- a/languages/codegen-sdk-python/src/lib.rs +++ b/languages/codegen-sdk-python/src/lib.rs @@ -12,12 +12,13 @@ pub mod ast { impl<'db> Scope<'db> for PythonFile<'db> { type Type = crate::cst::FunctionDefinition<'db>; type ReferenceType = crate::cst::Call<'db>; - #[salsa::tracked] + #[salsa::tracked(return_ref)] fn resolve(self, db: &'db dyn salsa::Database, name: String) -> Vec { + let tree = self.node(db).unwrap().tree(db); let mut results = Vec::new(); - for (def_name, defs) in self.definitions(db).functions.iter() { - if def_name == &name { - results.extend(defs.iter().cloned()); + for (def_name, defs) in self.definitions(db).functions(db, &tree).into_iter() { + if def_name == name { + results.extend(defs.into_iter().cloned()); } } results @@ -25,8 +26,9 @@ pub mod ast { #[salsa::tracked] fn resolvables(self, db: &'db dyn salsa::Database) -> Vec { let mut results = Vec::new(); - for (_, refs) in self.references(db).calls.into_iter() { - results.extend(refs); + let tree = self.node(db).unwrap().tree(db); + for (_, refs) in self.references(db).calls(db, &tree).into_iter() { + results.extend(refs.into_iter().cloned()); } results } @@ -34,14 +36,15 @@ pub mod ast { #[salsa::tracked] impl<'db> ResolveType<'db, PythonFile<'db>> for crate::cst::Call<'db> { type Type = crate::cst::FunctionDefinition<'db>; - #[salsa::tracked] + #[salsa::tracked(return_ref)] fn resolve_type( self, db: &'db dyn salsa::Database, scope: PythonFile<'db>, _scopes: Vec>, ) -> Vec { - scope.resolve(db, self.function.source()) + let tree = scope.node(db).unwrap().tree(db); + scope.resolve(db, self.function(tree).source()).clone() } } #[salsa::tracked] diff --git a/languages/codegen-sdk-python/tests/test_python.rs b/languages/codegen-sdk-python/tests/test_python.rs index 75084325..5d86b675 100644 --- a/languages/codegen-sdk-python/tests/test_python.rs +++ b/languages/codegen-sdk-python/tests/test_python.rs @@ -36,7 +36,8 @@ class Test: let content = codegen_sdk_cst::Input::new(&db, content.to_string()); let input = codegen_sdk_ast::input::File::new(&db, file_path, content); let file = codegen_sdk_python::ast::parse_query(&db, input); - assert_eq!(file.definitions(&db).classes.len(), 1); + let tree = file.tree(&db); + assert_eq!(file.definitions(&db).classes(&db, &tree).len(), 1); } #[test_log::test] fn test_python_ast_function() { @@ -49,7 +50,8 @@ def test(): let content = codegen_sdk_cst::Input::new(&db, content.to_string()); let input = codegen_sdk_ast::input::File::new(&db, file_path, content); let file = codegen_sdk_python::ast::parse_query(&db, input); - assert_eq!(file.definitions(&db).functions.len(), 1); + let tree = file.tree(&db); + assert_eq!(file.definitions(&db).functions(&db, &tree).len(), 1); } #[test_log::test] fn test_python_ast_function_usages() { @@ -64,11 +66,15 @@ test()"; let content = codegen_sdk_cst::Input::new(&db, content.to_string()); let input = codegen_sdk_ast::input::File::new(&db, file_path, content); let file = codegen_sdk_python::ast::parse_query(&db, input); - assert_eq!(file.references(&db).calls.len(), 1); + let tree = file.tree(&db); + assert_eq!(file.references(&db).calls(&db, &tree).len(), 1); let definitions = file.definitions(&db); - let function = definitions.functions.get("test").unwrap().first().unwrap(); + let functions = definitions.functions(&db, &tree); + let function = functions.get("test").unwrap().first().unwrap(); assert_eq!( - function.references_for_scopes(&db, vec![file], &file).len(), + function + .references_for_scopes(&db, vec![*file], &file) + .len(), 1 ); } diff --git a/languages/codegen-sdk-ruby/Cargo.toml b/languages/codegen-sdk-ruby/Cargo.toml index 93a214db..bb558304 100644 --- a/languages/codegen-sdk-ruby/Cargo.toml +++ b/languages/codegen-sdk-ruby/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree = { workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-rust/Cargo.toml b/languages/codegen-sdk-rust/Cargo.toml index 47504ba9..af96d5f0 100644 --- a/languages/codegen-sdk-rust/Cargo.toml +++ b/languages/codegen-sdk-rust/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree ={ workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-rust/src/lib.rs b/languages/codegen-sdk-rust/src/lib.rs index b45ffbeb..6afaa972 100644 --- a/languages/codegen-sdk-rust/src/lib.rs +++ b/languages/codegen-sdk-rust/src/lib.rs @@ -1,5 +1,5 @@ #![recursion_limit = "2048"] -#![allow(unused)] +#![allow(unused, irrefutable_let_patterns)] #![allow(non_snake_case)] pub mod cst { include!(concat!(env!("OUT_DIR"), "/rust.rs")); diff --git a/languages/codegen-sdk-toml/Cargo.toml b/languages/codegen-sdk-toml/Cargo.toml index 88de5b1c..2fb48bae 100644 --- a/languages/codegen-sdk-toml/Cargo.toml +++ b/languages/codegen-sdk-toml/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree = { workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-ts_query/Cargo.toml b/languages/codegen-sdk-ts_query/Cargo.toml index 65c8d4c2..75c07c05 100644 --- a/languages/codegen-sdk-ts_query/Cargo.toml +++ b/languages/codegen-sdk-ts_query/Cargo.toml @@ -9,10 +9,10 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } +indextree = { workspace = true } [build-dependencies] codegen-sdk-cst-generator = { workspace = true } codegen-sdk-common = { workspace = true, features = ["ts_query"] } diff --git a/languages/codegen-sdk-tsx/Cargo.toml b/languages/codegen-sdk-tsx/Cargo.toml index 014be1c0..d26ebc63 100644 --- a/languages/codegen-sdk-tsx/Cargo.toml +++ b/languages/codegen-sdk-tsx/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree = { workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/languages/codegen-sdk-typescript/Cargo.toml b/languages/codegen-sdk-typescript/Cargo.toml index c4e0ad0f..56445c6c 100644 --- a/languages/codegen-sdk-typescript/Cargo.toml +++ b/languages/codegen-sdk-typescript/Cargo.toml @@ -10,12 +10,12 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } log = { workspace = true } codegen-sdk-ast = { workspace = true } +indextree = { workspace = true } [build-dependencies] codegen-sdk-cst-generator = { workspace = true } codegen-sdk-ast-generator = { workspace = true } diff --git a/languages/codegen-sdk-typescript/tests/test_typescript.rs b/languages/codegen-sdk-typescript/tests/test_typescript.rs index 1ab0d82c..c7a59201 100644 --- a/languages/codegen-sdk-typescript/tests/test_typescript.rs +++ b/languages/codegen-sdk-typescript/tests/test_typescript.rs @@ -33,5 +33,6 @@ fn test_typescript_ast_interface() { let content = codegen_sdk_cst::Input::new(&db, content.to_string()); let input = codegen_sdk_ast::input::File::new(&db, file_path, content); let file = codegen_sdk_typescript::ast::parse_query(&db, input); - assert_eq!(file.definitions(&db).interfaces.len(), 1); + let tree = file.node(&db).unwrap().tree(&db); + assert_eq!(file.definitions(&db).interfaces(&db, &tree).len(), 1); } diff --git a/languages/codegen-sdk-yaml/Cargo.toml b/languages/codegen-sdk-yaml/Cargo.toml index 6defd948..2efebd0a 100644 --- a/languages/codegen-sdk-yaml/Cargo.toml +++ b/languages/codegen-sdk-yaml/Cargo.toml @@ -10,7 +10,7 @@ salsa = { workspace = true } tree-sitter = { workspace = true } derive_more = { workspace = true } ambassador = { workspace = true } -derive_generic_visitor = { workspace = true } +indextree = { workspace = true } subenum = {workspace = true} bytes = { workspace = true } codegen-sdk-cst = { workspace = true } diff --git a/src/main.rs b/src/main.rs index 0a85d1fc..c387676f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,19 +20,23 @@ fn get_total_definitions(codebase: &Codebase) -> Vec<(usize, usize, usize, usize #[cfg(feature = "typescript")] if let ParsedFile::Typescript(file) = parsed { let definitions = file.definitions(codebase.db()); - return ( - definitions.classes.len(), - definitions.functions.len(), - definitions.interfaces.len(), - definitions.methods.len(), - definitions.modules.len(), - 0, - ); + if let Some(node) = file.node(codebase.db()) { + let tree = node.tree(codebase.db()); + return ( + definitions.classes(codebase.db(), &tree).len(), + definitions.functions(codebase.db(), &tree).len(), + definitions.interfaces(codebase.db(), &tree).len(), + definitions.methods(codebase.db(), &tree).len(), + definitions.modules(codebase.db(), &tree).len(), + 0, + ); + } } #[cfg(feature = "python")] if let ParsedFile::Python(file) = parsed { let definitions = file.definitions(codebase.db()); - let functions = definitions.functions; + let tree = file.node(codebase.db()).unwrap().tree(codebase.db()); + let functions = definitions.functions(codebase.db(), &tree); let mut total_references = 0; let total_functions = functions.len(); for function in functions @@ -40,10 +44,12 @@ fn get_total_definitions(codebase: &Codebase) -> Vec<(usize, usize, usize, usize .map(|(_, functions)| functions) .flatten() { - total_references += function.references(codebase, file).len(); + total_references += function + .references_for_scopes(codebase.db(), vec![*file], &file) + .len(); } return ( - definitions.classes.len(), + definitions.classes(codebase.db(), &tree).len(), total_functions, 0, 0,