langs.rs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. //! Per-language specs: grammar + `.scm` query + (later) per-language config.
  2. //!
  3. //! Tier-1 languages are meant to be *mostly* a query file plus a small config
  4. //! here; logic queries can't express stays TS-side as a per-language `post()`
  5. //! hook over the returned buffers (see `src/extraction/kernel/route.ts`).
  6. //!
  7. //! Language strings are codegraph `Language` values (src/types.ts), not
  8. //! grammar names — `tsx` and `jsx` are separate entries that reuse another
  9. //! entry's grammar exactly like `WASM_GRAMMAR_FILES` does on the wasm path.
  10. use std::sync::OnceLock;
  11. use tree_sitter::{Language, Query};
  12. pub struct LangSpec {
  13. /// codegraph Language string (src/types.ts).
  14. pub name: &'static str,
  15. get_language: fn() -> Language,
  16. query_src: &'static str,
  17. language: OnceLock<Language>,
  18. query: OnceLock<Result<Query, String>>,
  19. }
  20. impl LangSpec {
  21. const fn new(name: &'static str, get_language: fn() -> Language, query_src: &'static str) -> Self {
  22. LangSpec {
  23. name,
  24. get_language,
  25. query_src,
  26. language: OnceLock::new(),
  27. query: OnceLock::new(),
  28. }
  29. }
  30. pub fn language(&self) -> &Language {
  31. self.language.get_or_init(self.get_language)
  32. }
  33. pub fn query(&self) -> Result<&Query, String> {
  34. self.query
  35. .get_or_init(|| {
  36. Query::new(self.language(), self.query_src)
  37. .map_err(|e| format!("query compile failed for {}: {e}", self.name))
  38. })
  39. .as_ref()
  40. .map_err(|e| e.clone())
  41. }
  42. }
  43. fn ts_language() -> Language {
  44. tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()
  45. }
  46. fn tsx_language() -> Language {
  47. tree_sitter_typescript::LANGUAGE_TSX.into()
  48. }
  49. fn js_language() -> Language {
  50. tree_sitter_javascript::LANGUAGE.into()
  51. }
  52. static TYPESCRIPT: LangSpec = LangSpec::new(
  53. "typescript",
  54. ts_language,
  55. include_str!("../queries/typescript.scm"),
  56. );
  57. static TSX: LangSpec = LangSpec::new("tsx", tsx_language, include_str!("../queries/typescript.scm"));
  58. static JAVASCRIPT: LangSpec = LangSpec::new(
  59. "javascript",
  60. js_language,
  61. include_str!("../queries/javascript.scm"),
  62. );
  63. static JSX: LangSpec = LangSpec::new("jsx", js_language, include_str!("../queries/javascript.scm"));
  64. pub static ALL: [&LangSpec; 4] = [&TYPESCRIPT, &TSX, &JAVASCRIPT, &JSX];
  65. pub fn spec_for(language: &str) -> Option<&'static LangSpec> {
  66. ALL.iter().find(|s| s.name == language).copied()
  67. }