diff --git a/CHANGELOG.md b/CHANGELOG.md index bd234e47af19..fedd2c2b6a2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b - The `--summary` reporter now reports parsing diagnostics too. Contributed by @ematipico +- Improved performance of GritQL queries by roughly 25-30%. Contributed by @arendjr + ### Configuration #### Bug fixes diff --git a/Cargo.lock b/Cargo.lock index 934ffc8f3c79..f71699e99604 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -641,7 +641,6 @@ dependencies = [ name = "biome_grit_patterns" version = "0.0.1" dependencies = [ - "anyhow", "biome_console", "biome_diagnostics", "biome_grit_parser", @@ -654,7 +653,6 @@ dependencies = [ "biome_test_utils", "grit-pattern-matcher", "grit-util", - "im", "insta", "path-absolutize", "rand 0.8.5", @@ -1269,15 +1267,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "bitmaps" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -dependencies = [ - "typenum", -] - [[package]] name = "bitvec" version = "1.0.1" @@ -2094,14 +2083,12 @@ dependencies = [ [[package]] name = "grit-pattern-matcher" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb91ad25bb8557f3be40899becf5db27e8431e359d69d5b67104f1d1a12c8d9a" +checksum = "8430b130e086a1764789402b34685336f2e3f6ec37cd188535bede892f88e65b" dependencies = [ - "anyhow", "elsa", "grit-util", - "im", "itertools", "rand 0.8.5", "regex", @@ -2109,14 +2096,15 @@ dependencies = [ [[package]] name = "grit-util" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4d302f12945a38d464183a6ffe49b8b778876f82ab753174324cd7aae74b24a" +checksum = "99b005c4c15ce0c47022554c41a01fe2441d3622e586a82614a6fe681833d5d4" dependencies = [ "derive_builder", "once_cell", "regex", "serde", + "thiserror", ] [[package]] @@ -2203,20 +2191,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "im" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" -dependencies = [ - "bitmaps", - "rand_core 0.6.4", - "rand_xoshiro", - "sized-chunks", - "typenum", - "version_check", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -3014,15 +2988,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core 0.6.4", -] - [[package]] name = "rayon" version = "1.10.0" @@ -3444,16 +3409,6 @@ dependencies = [ "similar", ] -[[package]] -name = "sized-chunks" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" -dependencies = [ - "bitmaps", - "typenum", -] - [[package]] name = "slab" version = "0.4.8" @@ -3951,12 +3906,6 @@ dependencies = [ "toml", ] -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "unicase" version = "2.6.0" diff --git a/crates/biome_grit_patterns/Cargo.toml b/crates/biome_grit_patterns/Cargo.toml index 80ef755e1410..90460cbf845d 100644 --- a/crates/biome_grit_patterns/Cargo.toml +++ b/crates/biome_grit_patterns/Cargo.toml @@ -12,7 +12,6 @@ repository.workspace = true version = "0.0.1" [dependencies] -anyhow = { workspace = true } biome_console = { workspace = true } biome_diagnostics = { workspace = true } biome_grit_parser = { workspace = true } @@ -22,9 +21,8 @@ biome_js_syntax = { workspace = true } biome_parser = { workspace = true } biome_rowan = { workspace = true } biome_string_case = { workspace = true } -grit-pattern-matcher = { version = "0.3" } -grit-util = { version = "0.3" } -im = { version = "15.1.0" } +grit-pattern-matcher = { version = "0.4" } +grit-util = { version = "0.4" } path-absolutize = { version = "3.1.1", optional = false, features = ["use_unix_paths_on_wasm"] } rand = { version = "0.8.5" } regex = { workspace = true } diff --git a/crates/biome_grit_patterns/src/grit_binding.rs b/crates/biome_grit_patterns/src/grit_binding.rs index d45dd4a3e989..fe37e19c8afc 100644 --- a/crates/biome_grit_patterns/src/grit_binding.rs +++ b/crates/biome_grit_patterns/src/grit_binding.rs @@ -2,13 +2,15 @@ use crate::{ grit_context::GritQueryContext, grit_target_language::GritTargetLanguage, grit_target_node::GritTargetNode, source_location_ext::SourceFileExt, util::TextRangeGritExt, }; -use anyhow::bail; use biome_diagnostics::{display::SourceFile, SourceCode}; use biome_rowan::TextRange; use grit_pattern_matcher::{ binding::Binding, constant::Constant, effects::Effect, pattern::FileRegistry, }; -use grit_util::{AnalysisLogBuilder, AnalysisLogs, AstNode, ByteRange, CodeRange, Range}; +use grit_util::{ + error::{GritPatternError, GritResult}, + AnalysisLogBuilder, AnalysisLogs, AstNode, ByteRange, CodeRange, Range, +}; use std::{borrow::Cow, collections::HashMap, path::Path}; #[derive(Clone, Debug, PartialEq)] @@ -161,11 +163,11 @@ impl<'a> Binding<'a, GritQueryContext> for GritBinding<'a> { _memo: &mut HashMap>, _distributed_indent: Option, _logs: &mut AnalysisLogs, - ) -> anyhow::Result> { - bail!("Not implemented") // TODO: Implement rewriting + ) -> GritResult> { + Err(GritPatternError::new("Not implemented")) // TODO: Implement rewriting } - fn text(&self, _language: &GritTargetLanguage) -> anyhow::Result> { + fn text(&self, _language: &GritTargetLanguage) -> GritResult> { match self { Self::File(path) => Ok(path.to_string_lossy()), Self::Node(node) => Ok(node.text().into()), @@ -249,9 +251,9 @@ impl<'a> Binding<'a, GritQueryContext> for GritBinding<'a> { &self, _language: &GritTargetLanguage, logs: &mut grit_util::AnalysisLogs, - ) -> anyhow::Result<()> { + ) -> GritResult<()> { if let Self::Empty(node, slot) = self { - let range = Range::from_byte_range(node.source(), node.byte_range()); + let range = Range::from_byte_range(node.source(), &node.byte_range()); let log = AnalysisLogBuilder::default() .level(441_u16) .source(node.source()) @@ -261,7 +263,8 @@ impl<'a> Binding<'a, GritQueryContext> for GritBinding<'a> { "Error: failed to rewrite binding, cannot derive range of empty slot {slot} of node with kind {:?}", node.kind() )) - .build()?; + .build() + .map_err(|error| GritPatternError::Builder(error.to_string()))?; logs.push(log); } diff --git a/crates/biome_grit_patterns/src/grit_built_in_functions.rs b/crates/biome_grit_patterns/src/grit_built_in_functions.rs index 00f8d110e198..95e14b276c05 100644 --- a/crates/biome_grit_patterns/src/grit_built_in_functions.rs +++ b/crates/biome_grit_patterns/src/grit_built_in_functions.rs @@ -2,29 +2,40 @@ use crate::{ grit_context::{GritExecContext, GritQueryContext}, grit_resolved_pattern::GritResolvedPattern, }; -use anyhow::{anyhow, bail, Result}; use biome_string_case::StrOnlyExtension; use grit_pattern_matcher::{ binding::Binding, constant::Constant, context::ExecContext, pattern::{ - get_absolute_file_name, CallBuiltIn, JoinFn, LazyBuiltIn, Pattern, ResolvedPattern, - ResolvedSnippet, State, + get_absolute_file_name, CallBuiltIn, CallbackPattern, JoinFn, LazyBuiltIn, Pattern, + ResolvedPattern, ResolvedSnippet, State, }, }; -use grit_util::AnalysisLogs; +use grit_util::{ + error::{GritPatternError, GritResult}, + AnalysisLogs, +}; use path_absolutize::Absolutize; use rand::{seq::SliceRandom, Rng}; -use std::borrow::Cow; use std::path::Path; +use std::{borrow::Cow, fmt::Debug, num::TryFromIntError}; pub type CallableFn = dyn for<'a> Fn( &'a [Option>], &'a GritExecContext<'a>, &mut State<'a, GritQueryContext>, &mut AnalysisLogs, - ) -> Result> + ) -> GritResult> + + Send + + Sync; + +pub type CallbackFn = dyn for<'a, 'b> Fn( + &'b GritResolvedPattern<'a>, + &'a GritExecContext<'a>, + &mut State<'a, GritQueryContext>, + &mut AnalysisLogs, + ) -> GritResult + Send + Sync; @@ -41,7 +52,7 @@ impl BuiltInFunction { context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, - ) -> Result> { + ) -> GritResult> { (self.func)(args, context, state, logs) } @@ -59,8 +70,19 @@ impl std::fmt::Debug for BuiltInFunction { } } -#[derive(Debug)] -pub struct BuiltIns(Vec); +pub struct BuiltIns { + built_ins: Vec, + callbacks: Vec>, +} + +impl Debug for BuiltIns { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "BuiltIns {{ built_ins: {:?} }}", + self.built_ins + )) + } +} impl Default for BuiltIns { fn default() -> Self { @@ -89,18 +111,40 @@ impl BuiltIns { context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, - ) -> Result> { - self.0[call.index].call(&call.args, context, state, logs) + ) -> GritResult> { + self.built_ins[call.index].call(&call.args, context, state, logs) + } + + pub(crate) fn call_callback<'a>( + &self, + call: &'a CallbackPattern, + context: &'a GritExecContext<'a>, + binding: &GritResolvedPattern<'a>, + state: &mut State<'a, GritQueryContext>, + logs: &mut AnalysisLogs, + ) -> GritResult { + (self.callbacks[call.callback_index])(binding, context, state, logs) + } + + /// Add an anonymous built-in, used for callbacks + /// Returns a pattern that can be used to call the callback + pub fn add_callback(&mut self, func: Box) -> Pattern { + self.callbacks.push(func); + let index = self.callbacks.len() - 1; + Pattern::CallbackPattern(Box::new(CallbackPattern::new(index))) } pub(crate) fn get_built_ins(&self) -> &[BuiltInFunction] { - &self.0 + &self.built_ins } } impl From> for BuiltIns { fn from(built_ins: Vec) -> Self { - Self(built_ins) + Self { + built_ins, + callbacks: Vec::new(), + } } } @@ -109,10 +153,12 @@ fn capitalize_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("capitalize() takes 1 argument: string"); + return Err(GritPatternError::new( + "capitalize() takes 1 argument: string", + )); }; let string = arg1.text(&state.files, context.language())?; @@ -126,10 +172,10 @@ fn distinct_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("distinct() takes 1 argument: list"); + return Err(GritPatternError::new("distinct() takes 1 argument: list")); }; match arg1 { @@ -145,7 +191,9 @@ fn distinct_fn<'a>( GritResolvedPattern::Binding(binding) => match binding.last() { Some(binding) => { let Some(list_items) = binding.list_items() else { - bail!("distinct() requires a list as the first argument"); + return Err(GritPatternError::new( + "distinct() requires a list as the first argument", + )); }; let mut unique_list = Vec::new(); @@ -159,7 +207,9 @@ fn distinct_fn<'a>( } None => Ok(GritResolvedPattern::Binding(binding)), }, - _ => bail!("distinct() requires a list as the first argument"), + _ => Err(GritPatternError::new( + "distinct() requires a list as the first argument", + )), } } @@ -168,11 +218,13 @@ fn join_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let mut args = args.into_iter(); let (Some(Some(arg1)), Some(Some(arg2))) = (args.next(), args.next()) else { - bail!("join() takes 2 arguments: list and separator"); + return Err(GritPatternError::new( + "join() takes 2 arguments: list and separator", + )); }; let separator = arg2.text(&state.files, context.language())?; @@ -181,7 +233,9 @@ fn join_fn<'a>( } else if let Some(items) = arg1.get_list_binding_items() { JoinFn::from_patterns(items, separator.to_string()) } else { - bail!("join() requires a list as the first argument"); + return Err(GritPatternError::new( + "join() requires a list as the first argument", + )); }; let snippet = ResolvedSnippet::LazyFn(Box::new(LazyBuiltIn::Join(join))); @@ -193,33 +247,51 @@ fn length_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("length() takes 1 argument: list or string"); + return Err(GritPatternError::new( + "length() takes 1 argument: list or string", + )); }; Ok(match arg1 { - GritResolvedPattern::List(list) => { - ResolvedPattern::from_constant(Constant::Integer(list.len().try_into()?)) - } - GritResolvedPattern::Binding(binding) => match binding.last() { - Some(resolved_pattern) => { - let length = if let Some(list_items) = resolved_pattern.list_items() { - list_items.count() - } else { - resolved_pattern.text(context.language())?.len() - }; - ResolvedPattern::from_constant(Constant::Integer(length.try_into()?)) + GritResolvedPattern::List(list) => ResolvedPattern::from_constant(Constant::Integer( + list.len() + .try_into() + .map_err(|error: TryFromIntError| GritPatternError::new(error.to_string()))?, + )), + GritResolvedPattern::Binding(binding) => { + match binding.last() { + Some(resolved_pattern) => { + let length = if let Some(list_items) = resolved_pattern.list_items() { + list_items.count() + } else { + resolved_pattern.text(context.language())?.len() + }; + ResolvedPattern::from_constant(Constant::Integer(length.try_into().map_err( + |error: TryFromIntError| GritPatternError::new(error.to_string()), + )?)) + } + None => { + return Err(GritPatternError::new( + "length() requires a list or string as the first argument", + )) + } } - None => bail!("length() requires a list or string as the first argument"), - }, + } resolved_pattern => { let Ok(text) = resolved_pattern.text(&state.files, context.language()) else { - bail!("length() requires a list or string as the first argument"); + return Err(GritPatternError::new( + "length() requires a list or string as the first argument", + )); }; - ResolvedPattern::from_constant(Constant::Integer(text.len().try_into()?)) + ResolvedPattern::from_constant(Constant::Integer( + text.len() + .try_into() + .map_err(|error: TryFromIntError| GritPatternError::new(error.to_string()))?, + )) } }) } @@ -229,10 +301,12 @@ fn lowercase_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("lowercase() takes 1 argument: string"); + return Err(GritPatternError::new( + "lowercase() takes 1 argument: string", + )); }; let string = arg1.text(&state.files, context.language())?; @@ -246,7 +320,7 @@ fn random_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; match args.as_slice() { @@ -263,7 +337,9 @@ fn random_fn<'a>( let value = state.get_rng().gen::(); Ok(ResolvedPattern::from_constant(Constant::Float(value))) } - _ => bail!("random() takes 0 or 2 arguments: an optional start and end"), + _ => Err(GritPatternError::new( + "random() takes 0 or 2 arguments: an optional start and end", + )), } } @@ -273,10 +349,10 @@ fn resolve_path_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("resolve() takes 1 argument: path"); + return Err(GritPatternError::new("resolve() takes 1 argument: path")); }; let current_file = get_absolute_file_name(state, context.language())?; @@ -292,10 +368,10 @@ fn shuffle_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("shuffle() takes 1 argument: list"); + return Err(GritPatternError::new("shuffle() takes 1 argument: list")); }; let mut list: Vec<_> = if let Some(items) = arg1.get_list_items() { @@ -303,7 +379,9 @@ fn shuffle_fn<'a>( } else if let Some(items) = arg1.get_list_binding_items() { items.collect() } else { - bail!("shuffle() requires a list as the first argument"); + return Err(GritPatternError::new( + "shuffle() requires a list as the first argument", + )); }; list.shuffle(state.get_rng()); @@ -315,11 +393,13 @@ fn split_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let mut args = args.into_iter(); let (Some(Some(arg1)), Some(Some(arg2))) = (args.next(), args.next()) else { - bail!("split() takes 2 arguments: string and separator"); + return Err(GritPatternError::new( + "split() takes 2 arguments: string and separator", + )); }; let separator = arg2.text(&state.files, context.language())?; @@ -337,10 +417,10 @@ fn text_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("text() takes 1 argument: string"); + return Err(GritPatternError::new("text() takes 1 argument: string")); }; let string = arg1.text(&state.files, context.language())?; @@ -352,11 +432,13 @@ fn trim_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let mut args = args.into_iter(); let (Some(Some(arg1)), Some(Some(arg2))) = (args.next(), args.next()) else { - bail!("trim() takes 2 arguments: string and trim_chars"); + return Err(GritPatternError::new( + "trim() takes 2 arguments: string and trim_chars", + )); }; let trim_chars = arg2.text(&state.files, context.language())?; @@ -373,10 +455,12 @@ fn uppercase_fn<'a>( context: &'a GritExecContext<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, -) -> Result> { +) -> GritResult> { let args = GritResolvedPattern::from_patterns(args, state, context, logs)?; let Some(Some(arg1)) = args.into_iter().next() else { - bail!("uppercase() takes 1 argument: string"); + return Err(GritPatternError::new( + "uppercase() takes 1 argument: string", + )); }; let string = arg1.text(&state.files, context.language())?; @@ -393,14 +477,19 @@ fn capitalize(s: &str) -> Cow { Cow::Borrowed(s) } -fn resolve<'a>(target_path: Cow<'a, str>, from_file: Cow<'a, str>) -> Result { +fn resolve<'a>(target_path: Cow<'a, str>, from_file: Cow<'a, str>) -> GritResult { let Some(source_path) = Path::new(from_file.as_ref()).parent() else { - bail!("could not get parent directory of file name {}", &from_file); + return Err(GritPatternError::new(format!( + "could not get parent directory of file name {}", + &from_file, + ))); }; let our_path = Path::new(target_path.as_ref()); let absolutized = our_path.absolutize_from(source_path)?; Ok(absolutized .to_str() - .ok_or_else(|| anyhow!("could not build absolute path from file name {target_path}"))? + .ok_or_else(|| { + GritPatternError::new("could not build absolute path from file name {target_path}") + })? .to_owned()) } diff --git a/crates/biome_grit_patterns/src/grit_code_snippet.rs b/crates/biome_grit_patterns/src/grit_code_snippet.rs index 46fc98a188eb..1e3c49338f4c 100644 --- a/crates/biome_grit_patterns/src/grit_code_snippet.rs +++ b/crates/biome_grit_patterns/src/grit_code_snippet.rs @@ -1,12 +1,12 @@ use crate::grit_context::{GritExecContext, GritQueryContext}; use crate::grit_resolved_pattern::GritResolvedPattern; use crate::grit_target_node::GritTargetSyntaxKind; -use anyhow::Result; use grit_pattern_matcher::binding::Binding; use grit_pattern_matcher::context::ExecContext; use grit_pattern_matcher::pattern::{ CodeSnippet, DynamicPattern, Matcher, Pattern, PatternName, ResolvedPattern, State, }; +use grit_util::error::GritResult; use grit_util::AnalysisLogs; #[derive(Clone, Debug)] @@ -33,7 +33,7 @@ impl Matcher for GritCodeSnippet { state: &mut State<'a, GritQueryContext>, context: &'a GritExecContext, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { let Some(binding) = resolved.get_last_binding() else { return Ok(resolved.text(&state.files, context.language())?.trim() == self.source); }; diff --git a/crates/biome_grit_patterns/src/grit_context.rs b/crates/biome_grit_patterns/src/grit_context.rs index 5d29a8f1d226..74244c12fced 100644 --- a/crates/biome_grit_patterns/src/grit_context.rs +++ b/crates/biome_grit_patterns/src/grit_context.rs @@ -7,7 +7,6 @@ use crate::grit_resolved_pattern::GritResolvedPattern; use crate::grit_target_language::GritTargetLanguage; use crate::grit_target_node::GritTargetNode; use crate::grit_tree::GritTargetTree; -use anyhow::{anyhow, bail, Result}; use biome_parser::AnyParse; use grit_pattern_matcher::constants::{GLOBAL_VARS_SCOPE_INDEX, NEW_FILES_INDEX}; use grit_pattern_matcher::context::{ExecContext, QueryContext}; @@ -16,8 +15,8 @@ use grit_pattern_matcher::pattern::{ CallBuiltIn, File, FilePtr, GritFunctionDefinition, Matcher, Pattern, PatternDefinition, PredicateDefinition, ResolvedPattern, State, }; -use grit_util::{AnalysisLogs, FileOrigin, InputRanges, MatchRanges}; -use im::vector; +use grit_util::error::GritPatternError; +use grit_util::{error::GritResult, AnalysisLogs, FileOrigin, InputRanges, MatchRanges}; use path_absolutize::Absolutize; use std::path::PathBuf; @@ -75,8 +74,23 @@ impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext<'a> { context: &'a Self, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, - ) -> Result> { - self.built_ins.call(call, context, state, logs) + ) -> GritResult> { + self.built_ins + .call(call, context, state, logs) + .map_err(|e| GritPatternError::new(e.to_string())) + } + + fn call_callback<'b>( + &self, + call: &'a grit_pattern_matcher::pattern::CallbackPattern, + context: &'a Self, + binding: &'b ::ResolvedPattern<'a>, + state: &mut State<'a, GritQueryContext>, + logs: &mut AnalysisLogs, + ) -> GritResult { + self.built_ins + .call_callback(call, context, binding, state, logs) + .map_err(|e| GritPatternError::new(e.to_string())) } fn files(&self) -> &FileOwners { @@ -93,7 +107,7 @@ impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext<'a> { binding: &GritResolvedPattern, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { let mut files = if let Some(files) = binding.get_file_pointers() { files .iter() @@ -139,8 +153,9 @@ impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext<'a> { // TODO: Implement effect application } - let new_files_binding = - &mut state.bindings[GLOBAL_VARS_SCOPE_INDEX].back_mut().unwrap()[NEW_FILES_INDEX]; + let new_files_binding = &mut state.bindings[GLOBAL_VARS_SCOPE_INDEX as usize] + .last_mut() + .unwrap()[NEW_FILES_INDEX]; if new_files_binding.value.is_none() { new_files_binding.value = Some(GritResolvedPattern::from_list_parts([].into_iter())); } @@ -150,12 +165,12 @@ impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext<'a> { .as_ref() .and_then(ResolvedPattern::get_list_items) else { - bail!("Expected a list of files") + return Err(GritPatternError::new("Expected a list of files")); }; for f in new_files { let Some(file) = f.get_file() else { - bail!("Expected a list of files") + return Err(GritPatternError::new("Expected a list of files")); }; let name: PathBuf = file @@ -166,17 +181,17 @@ impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext<'a> { let body = file.body(&state.files).text(&state.files, &self.lang)?; let owned_file = new_file_owner(name.clone(), &body, &self.lang, logs)?.ok_or_else(|| { - anyhow!( + GritPatternError::Builder(format!( "failed to construct new file for file {}", name.to_string_lossy() - ) + )) })?; self.files().push(owned_file); // SAFETY: We just pushed to the list of files, so there must be one. let _ = state.files.push_new_file(self.files().last().unwrap()); } - state.effects = vector![]; + state.effects = vec![]; new_files_binding.value = Some(ResolvedPattern::from_list_parts([].into_iter())); Ok(true) } @@ -190,7 +205,7 @@ impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext<'a> { file: &GritFile<'a>, state: &mut State<'a, GritQueryContext>, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { match file { GritFile::Resolved(_) => { // Assume the file is already loaded @@ -230,7 +245,7 @@ fn file_owner_from_matches( old_tree: FileOrigin<'_, GritTargetTree>, language: &GritTargetLanguage, logs: &mut AnalysisLogs, -) -> Result>> { +) -> GritResult>> { let name = name.into(); let new = !old_tree.is_fresh(); @@ -256,7 +271,7 @@ fn new_file_owner( source: &str, language: &GritTargetLanguage, logs: &mut AnalysisLogs, -) -> Result>> { +) -> GritResult>> { let name = name.into(); let Some(tree) = language diff --git a/crates/biome_grit_patterns/src/grit_file.rs b/crates/biome_grit_patterns/src/grit_file.rs index a22ab7617ba0..4c6aa44391a3 100644 --- a/crates/biome_grit_patterns/src/grit_file.rs +++ b/crates/biome_grit_patterns/src/grit_file.rs @@ -7,7 +7,7 @@ use grit_pattern_matcher::{ constant::Constant, pattern::{File, FilePtr, FileRegistry, ResolvedFile, ResolvedPattern}, }; -use grit_util::Ast; +use grit_util::{error::GritResult, Ast}; use path_absolutize::Absolutize; #[derive(Clone, Debug, PartialEq)] @@ -28,7 +28,7 @@ impl<'a> File<'a, GritQueryContext> for GritFile<'a> { &self, files: &FileRegistry<'a, GritQueryContext>, language: &GritTargetLanguage, - ) -> anyhow::Result> { + ) -> GritResult> { match self { Self::Resolved(resolved) => { let name = resolved.name.text(files, language)?; diff --git a/crates/biome_grit_patterns/src/grit_node.rs b/crates/biome_grit_patterns/src/grit_node.rs index b08170d5af1e..4ad225bace98 100644 --- a/crates/biome_grit_patterns/src/grit_node.rs +++ b/crates/biome_grit_patterns/src/grit_node.rs @@ -1,7 +1,7 @@ use crate::util::TextRangeGritExt; use biome_grit_syntax::GritSyntaxNode; -use grit_util::{AstCursor, AstNode as GritAstNode, ByteRange, CodeRange}; -use std::{borrow::Cow, ops::Deref, str::Utf8Error}; +use grit_util::{error::GritResult, AstCursor, AstNode as GritAstNode, ByteRange, CodeRange}; +use std::{borrow::Cow, ops::Deref}; /// Wrapper around `GritSyntaxNode` as produced by our internal Grit parser. /// @@ -71,7 +71,7 @@ impl GritAstNode for GritNode { self.0.prev_sibling().map(Into::into) } - fn text(&self) -> Result, Utf8Error> { + fn text(&self) -> GritResult> { Ok(Cow::Owned(self.0.text_trimmed().to_string())) } diff --git a/crates/biome_grit_patterns/src/grit_node_patterns.rs b/crates/biome_grit_patterns/src/grit_node_patterns.rs index 0e050ea6304c..3f8dcc48c317 100644 --- a/crates/biome_grit_patterns/src/grit_node_patterns.rs +++ b/crates/biome_grit_patterns/src/grit_node_patterns.rs @@ -3,13 +3,13 @@ use crate::grit_resolved_pattern::GritResolvedPattern; use crate::grit_target_language::LeafEquivalenceClass; use crate::grit_target_node::{GritTargetNode, GritTargetSyntaxKind}; use crate::{CompileError, GritTargetLanguage}; -use anyhow::Result; use grit_pattern_matcher::binding::Binding; -use grit_pattern_matcher::context::ExecContext; +use grit_pattern_matcher::context::{ExecContext, StaticDefinitions}; use grit_pattern_matcher::pattern::{ AstLeafNodePattern, AstNodePattern, Matcher, Pattern, PatternName, PatternOrPredicate, ResolvedPattern, State, }; +use grit_util::error::GritResult; use grit_util::{AnalysisLogs, Language}; #[derive(Clone, Debug)] @@ -21,7 +21,10 @@ pub struct GritNodePattern { impl AstNodePattern for GritNodePattern { const INCLUDES_TRIVIA: bool = true; - fn children(&self) -> Vec> { + fn children( + &self, + _definitions: &StaticDefinitions, + ) -> Vec> { self.args .iter() .map(|arg| PatternOrPredicate::Pattern(&arg.pattern)) @@ -40,7 +43,7 @@ impl Matcher for GritNodePattern { init_state: &mut State<'a, GritQueryContext>, context: &'a GritExecContext, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { let Some(binding) = binding.get_last_binding() else { return Ok(false); }; @@ -161,7 +164,7 @@ impl Matcher for GritLeafNodePattern { _state: &mut State<'a, GritQueryContext>, _context: &'a GritExecContext, _logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { let Some(node) = binding.get_last_binding().and_then(Binding::singleton) else { return Ok(false); }; diff --git a/crates/biome_grit_patterns/src/grit_query.rs b/crates/biome_grit_patterns/src/grit_query.rs index 6e5d068a6c94..31ed5f72d728 100644 --- a/crates/biome_grit_patterns/src/grit_query.rs +++ b/crates/biome_grit_patterns/src/grit_query.rs @@ -13,18 +13,16 @@ use crate::pattern_compiler::{ }; use crate::variables::{VarRegistry, VariableLocations}; use crate::CompileError; -use anyhow::bail; -use anyhow::Result; use biome_grit_syntax::{GritRoot, GritRootExt}; use grit_pattern_matcher::constants::{ ABSOLUTE_PATH_INDEX, FILENAME_INDEX, NEW_FILES_INDEX, PROGRAM_INDEX, }; use grit_pattern_matcher::file_owners::{FileOwner, FileOwners}; use grit_pattern_matcher::pattern::{ - FilePtr, FileRegistry, Matcher, Pattern, ResolvedPattern, State, VariableSourceLocations, + FilePtr, FileRegistry, Matcher, Pattern, ResolvedPattern, State, VariableSource, }; +use grit_util::error::{GritPatternError, GritResult}; use grit_util::{AnalysisLogs, Ast, ByteRange, InputRanges, Range, VariableMatch}; -use im::Vector; use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -64,7 +62,10 @@ pub struct GritQuery { } impl GritQuery { - pub fn execute(&self, file: GritTargetFile) -> Result<(Vec, AnalysisLogs)> { + pub fn execute( + &self, + file: GritTargetFile, + ) -> GritResult<(Vec, AnalysisLogs)> { let file_owners = FileOwners::new(); let files = vec![file]; let file_ptr = FilePtr::new(0, 0); @@ -125,14 +126,14 @@ impl GritQuery { let mut vars_array = vec![GLOBAL_VARS .iter() - .map(|global_var| VariableSourceLocations { + .map(|global_var| VariableSource::Compiled { name: global_var.0.to_string(), file: source_path .map(Path::to_string_lossy) .map_or_else(|| "unnamed".to_owned(), |p| p.to_string()), locations: BTreeSet::new(), }) - .collect::>()]; + .collect::>()]; let mut global_vars: BTreeMap = GLOBAL_VARS .iter() .map(|(global_var, index)| ((*global_var).to_string(), *index)) @@ -193,9 +194,9 @@ pub enum GritQueryResult { } impl GritQueryResult { - pub fn from_file(file: &Vector<&FileOwner>) -> anyhow::Result> { + pub fn from_file(file: &[&FileOwner]) -> GritResult> { if file.is_empty() { - bail!("cannot have file with no versions") + return Err(GritPatternError::new("cannot have file with no versions")); } let result = if file.len() == 1 { @@ -218,8 +219,8 @@ impl GritQueryResult { } } else { Some(GritQueryResult::Rewrite(Rewrite::from_file( - file.front().unwrap(), - file.back().unwrap(), + file.first().unwrap(), + file.last().unwrap(), )?)) }; @@ -296,11 +297,11 @@ impl Rewrite { fn from_file( initial: &FileOwner, rewritten_file: &FileOwner, - ) -> anyhow::Result { + ) -> GritResult { let original = if let Some(ranges) = &initial.matches.borrow().input_matches { Match::from_file_ranges(ranges, &initial.name) } else { - bail!("cannot have rewrite without matches") + return Err(GritPatternError::new("cannot have rewrite without matches")); }; let rewritten = OutputFile::from_file(rewritten_file); Ok(Rewrite::new(original, rewritten)) diff --git a/crates/biome_grit_patterns/src/grit_resolved_pattern.rs b/crates/biome_grit_patterns/src/grit_resolved_pattern.rs index c5b32cffd709..7ca1a79332cd 100644 --- a/crates/biome_grit_patterns/src/grit_resolved_pattern.rs +++ b/crates/biome_grit_patterns/src/grit_resolved_pattern.rs @@ -5,7 +5,6 @@ use crate::grit_target_node::GritTargetNode; use crate::grit_tree::GritTargetTree; use crate::GritTargetLanguage; use crate::{grit_binding::GritBinding, grit_context::GritQueryContext}; -use anyhow::{anyhow, bail, Error, Result}; use grit_pattern_matcher::binding::Binding; use grit_pattern_matcher::constant::Constant; use grit_pattern_matcher::context::{ExecContext, QueryContext}; @@ -15,6 +14,7 @@ use grit_pattern_matcher::pattern::{ FileRegistry, GritCall, ListIndex, Pattern, PatternName, PatternOrResolved, ResolvedFile, ResolvedPattern, ResolvedSnippet, State, }; +use grit_util::error::{GritPatternError, GritResult}; use grit_util::{AnalysisLogs, Ast, CodeRange, Range}; use std::borrow::Cow; use std::collections::{BTreeMap, HashMap}; @@ -39,14 +39,16 @@ impl<'a> GritResolvedPattern<'a> { Self::from_binding(GritBinding::from_node(tree.root_node())) } - fn to_snippets(&self) -> Result>> { + fn to_snippets(&self) -> GritResult>> { match self { Self::Snippets(snippets) => Ok(snippets.clone()), Self::Binding(bindings) => Ok(vec![ResolvedSnippet::from_binding( bindings .last() .ok_or_else(|| { - anyhow::anyhow!("cannot create resolved snippet from unresolved binding") + GritPatternError::new( + "cannot create resolved snippet from unresolved binding", + ) })? .to_owned(), )]), @@ -72,11 +74,11 @@ impl<'a> GritResolvedPattern<'a> { snippets.push(ResolvedSnippet::Text("}".into())); Ok(snippets) } - Self::File(_) => Err(anyhow::anyhow!( - "cannot convert ResolvedPattern::File to ResolvedSnippet" + Self::File(_) => Err(GritPatternError::new( + "cannot convert ResolvedPattern::File to ResolvedSnippet", )), - Self::Files(_) => Err(anyhow::anyhow!( - "cannot convert ResolvedPattern::Files to ResolvedSnippet" + Self::Files(_) => Err(GritPatternError::new( + "cannot convert ResolvedPattern::Files to ResolvedSnippet", )), Self::Constant(constant) => { Ok(vec![ResolvedSnippet::Text(constant.to_string().into())]) @@ -119,7 +121,7 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { state: &mut State<'a, GritQueryContext>, context: &'a GritExecContext, logs: &mut grit_util::AnalysisLogs, - ) -> anyhow::Result { + ) -> GritResult { let mut parts = Vec::new(); for part in &snippet.parts { match part { @@ -127,7 +129,9 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { parts.push(ResolvedSnippet::Text(string.into())); } DynamicSnippetPart::Variable(var) => { - let content = &state.bindings[var.scope].last().unwrap()[var.index]; + let content = &state.bindings[var.try_scope().unwrap() as usize] + .last() + .unwrap()[var.try_index().unwrap() as usize]; let name = &content.name; // feels weird not sure if clone is correct let value = if let Some(value) = &content.value { @@ -135,9 +139,9 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { } else if let Some(pattern) = content.pattern { Self::from_pattern(pattern, state, context, logs)? } else { - anyhow::bail!( + return Err(GritPatternError::new(format!( "cannot create resolved snippet from unresolved variable {name}" - ) + ))); }; let value = value.to_snippets()?; parts.extend(value); @@ -152,10 +156,12 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { state: &mut State<'a, GritQueryContext>, context: &'a GritExecContext, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { match pattern { DynamicPattern::Variable(var) => { - let content = &state.bindings[var.scope].last().unwrap()[var.index]; + let content = &state.bindings[var.try_scope().unwrap() as usize] + .last() + .unwrap()[var.try_index().unwrap() as usize]; let name = &content.name; // feels weird not sure if clone is correct if let Some(value) = &content.value { @@ -163,7 +169,10 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { } else if let Some(pattern) = content.pattern { Self::from_pattern(pattern, state, context, logs) } else { - anyhow::bail!("cannot create resolved snippet from unresolved variable {name}") + return Err(GritPatternError::new(format!( + "cannot create resolved snippet from unresolved variable {}", + name + ))); } } DynamicPattern::Accessor(accessor) => { @@ -191,7 +200,7 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { state: &mut State<'a, GritQueryContext>, context: &'a GritExecContext, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { match accessor.get(state, context.language())? { Some(PatternOrResolved::Pattern(pattern)) => { Self::from_pattern(pattern, state, context, logs) @@ -207,7 +216,7 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { state: &mut State<'a, GritQueryContext>, context: &'a GritExecContext, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { match index.get(state, context.language())? { Some(PatternOrResolved::Pattern(pattern)) => { Self::from_pattern(pattern, state, context, logs) @@ -223,7 +232,7 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { state: &mut State<'a, GritQueryContext>, context: &'a GritExecContext, logs: &mut AnalysisLogs, - ) -> Result { + ) -> GritResult { match pattern { Pattern::Dynamic(pattern) => Self::from_dynamic_pattern(pattern, state, context, logs), Pattern::CodeSnippet(GritCodeSnippet { @@ -233,6 +242,10 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { Pattern::CallBuiltIn(built_in) => built_in.call(state, context, logs), Pattern::CallFunction(func) => func.call(state, context, logs), Pattern::CallForeignFunction(_) => unimplemented!(), + Pattern::CallbackPattern(callback) => Err(GritPatternError::new(format!( + "cannot make resolved pattern from callback pattern {}", + callback.name() + ))), Pattern::StringConstant(string) => Ok(Self::Snippets(vec![ResolvedSnippet::Text( (&string.text).into(), )])), @@ -240,7 +253,9 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { Pattern::FloatConstant(double) => Ok(Self::Constant(Constant::Float(double.value))), Pattern::BooleanConstant(bool) => Ok(Self::Constant(Constant::Boolean(bool.value))), Pattern::Variable(var) => { - let content = &state.bindings[var.scope].last().unwrap()[var.index]; + let content = &state.bindings[var.try_scope().unwrap() as usize] + .last() + .unwrap()[var.try_index().unwrap() as usize]; let name = &content.name; // feels weird not sure if clone is correct if let Some(value) = &content.value { @@ -248,14 +263,17 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { } else if let Some(pattern) = content.pattern { Self::from_pattern(pattern, state, context, logs) } else { - anyhow::bail!("cannot create resolved snippet from unresolved variable {name}") + return Err(GritPatternError::new(format!( + "cannot create resolved snippet from unresolved variable {}", + name + ))); } } Pattern::List(list) => list .patterns .iter() .map(|pattern| Self::from_pattern(pattern, state, context, logs)) - .collect::>>() + .collect::>>() .map(Self::List), Pattern::ListIndex(index) => Self::from_list_index(index, state, context, logs), Pattern::Map(map) => map @@ -267,7 +285,7 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { Self::from_pattern(value, state, context, logs)?, )) }) - .collect::>>() + .collect::>>() .map(Self::Map), Pattern::Accessor(accessor) => Self::from_accessor(accessor, state, context, logs), Pattern::File(file_pattern) => { @@ -320,7 +338,7 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { | Pattern::Every(_) | Pattern::Dots | Pattern::Like(_) - | Pattern::Sequential(_) => Err(anyhow::anyhow!(format!( + | Pattern::Sequential(_) => Err(GritPatternError::new(format!( "cannot make resolved pattern from arbitrary pattern {}", pattern.name() ))), @@ -330,44 +348,44 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { fn extend( &mut self, _with: Self, - _effects: &mut im::Vector>, + _effects: &mut Vec>, _language: &::Language<'a>, - ) -> anyhow::Result<()> { - bail!("Not implemented") // TODO: Implement rewriting + ) -> GritResult<()> { + Err(GritPatternError::new("Not implemented")) // TODO: Implement rewriting } fn float( &self, state: &FileRegistry<'a, GritQueryContext>, language: &GritTargetLanguage, - ) -> Result { + ) -> GritResult { match self { Self::Constant(c) => match c { Constant::Float(d) => Ok(*d), Constant::Integer(i) => Ok(*i as f64), Constant::String(s) => Ok(s.parse::()?), - Constant::Boolean(_) | Constant::Undefined => Err(anyhow::anyhow!("Cannot convert constant to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.")), + Constant::Boolean(_) | Constant::Undefined => Err(GritPatternError::new("Cannot convert constant to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.")), }, Self::Snippets(s) => { let text = s .iter() .map(|snippet| snippet.text(state, language)) - .collect::>>()? + .collect::>>()? .join(""); text.parse::().map_err(|_| { - anyhow::anyhow!("Failed to convert snippet to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.") + GritPatternError::new("Failed to convert snippet to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.") }) } Self::Binding(binding) => { let text = binding .last() - .ok_or_else(|| anyhow::anyhow!("cannot grab text of resolved_pattern with no binding"))? + .ok_or_else(|| GritPatternError::new("cannot grab text of resolved_pattern with no binding"))? .text(language)?; text.parse::().map_err(|_| { - anyhow::anyhow!("Failed to convert binding to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.") + GritPatternError::new("Failed to convert binding to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.") }) } - Self::List(_) | Self::Map(_) | Self::File(_) | Self::Files(_) => Err(anyhow::anyhow!("Cannot convert type to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.")), + Self::List(_) | Self::Map(_) | Self::File(_) | Self::Files(_) => Err(GritPatternError::new("Cannot convert type to double. Ensure that you are only attempting arithmetic operations on numeric-parsable types.")), } } @@ -481,7 +499,7 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { &self, state: &mut State<'a, GritQueryContext>, language: &GritTargetLanguage, - ) -> Result { + ) -> GritResult { let truthiness = match self { Self::Binding(bindings) => bindings.last().map_or(false, Binding::is_truthy), Self::List(elements) => !elements.is_empty(), @@ -508,8 +526,8 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { _memo: &mut HashMap>, _should_pad_snippet: bool, _logs: &mut AnalysisLogs, - ) -> Result> { - bail!("Not implemented") // TODO: Implement rewriting + ) -> GritResult> { + Err(GritPatternError::new("Not implemented")) // TODO: Implement rewriting } fn matches_undefined(&self) -> bool { @@ -538,8 +556,8 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { _binding: &GritBinding, _is_first: bool, _language: &GritTargetLanguage, - ) -> Result<()> { - bail!("Not implemented") // TODO: Implement insertion padding + ) -> GritResult<()> { + Err(GritPatternError::new("Not implemented")) // TODO: Implement insertion padding } fn position(&self, language: &GritTargetLanguage) -> Option { @@ -552,18 +570,18 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { None } - fn push_binding(&mut self, binding: GritBinding<'a>) -> Result<()> { + fn push_binding(&mut self, binding: GritBinding<'a>) -> GritResult<()> { let Self::Binding(bindings) = self else { - bail!("can only push to bindings"); + return Err(GritPatternError::new("can only push to bindings")); }; bindings.push(binding); Ok(()) } - fn set_list_item_at_mut(&mut self, index: isize, value: Self) -> Result { + fn set_list_item_at_mut(&mut self, index: isize, value: Self) -> GritResult { let Self::List(items) = self else { - bail!("can only set items on a list"); + return Err(GritPatternError::new("can only set items on a list")); }; let Some(index) = to_unsigned(index, items.len()) else { @@ -578,11 +596,13 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { &self, state: &FileRegistry<'a, GritQueryContext>, language: &GritTargetLanguage, - ) -> Result> { + ) -> GritResult> { match self { Self::Binding(bindings) => Ok(bindings .last() - .ok_or_else(|| anyhow!("cannot grab text of resolved_pattern with no binding"))? + .ok_or_else(|| { + GritPatternError::new("cannot grab text of resolved_pattern with no binding") + })? .text(language)? .into_owned() .into()), @@ -590,13 +610,13 @@ impl<'a> ResolvedPattern<'a, GritQueryContext> for GritResolvedPattern<'a> { .iter() .try_fold(String::new(), |mut text, snippet| { text.push_str(&snippet.text(state, language)?); - Ok::(text) + Ok::(text) })? .into()), Self::List(list) => Ok(list .iter() .map(|pattern| pattern.text(state, language)) - .collect::>>()? + .collect::>>()? .join(",") .into()), Self::Map(map) => Ok(format!( diff --git a/crates/biome_grit_patterns/src/grit_target_node.rs b/crates/biome_grit_patterns/src/grit_target_node.rs index fbbc60b26b3e..c37e7ec10bd0 100644 --- a/crates/biome_grit_patterns/src/grit_target_node.rs +++ b/crates/biome_grit_patterns/src/grit_target_node.rs @@ -2,8 +2,8 @@ use crate::grit_tree::GritTargetTree; use crate::util::TextRangeGritExt; use biome_js_syntax::{JsSyntaxKind, JsSyntaxNode, JsSyntaxToken}; use biome_rowan::{NodeOrToken, SyntaxKind, SyntaxSlot, TextRange}; -use grit_util::{AstCursor, AstNode as GritAstNode, ByteRange, CodeRange}; -use std::{borrow::Cow, fmt::Debug, ops::Deref, str::Utf8Error}; +use grit_util::{error::GritResult, AstCursor, AstNode as GritAstNode, ByteRange, CodeRange}; +use std::{borrow::Cow, fmt::Debug, ops::Deref}; use NodeOrToken::*; @@ -384,7 +384,7 @@ impl<'a> GritAstNode for GritTargetNode<'a> { } } - fn text(&self) -> Result, Utf8Error> { + fn text(&self) -> GritResult> { Ok(Cow::Borrowed(self.text())) } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/accumulate_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/accumulate_compiler.rs index dcd9385a3bf5..e81b32cfa37c 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/accumulate_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/accumulate_compiler.rs @@ -15,13 +15,13 @@ impl AccumulateCompiler { ) -> Result, CompileError> { let left = PatternCompiler::from_node(&node.left()?, context)?; let right = PatternCompiler::from_node_with_rhs(&node.right()?, context, true)?; - let dynamic_right = match &right { - Pattern::Dynamic(r) => Some(r.clone()), + let dynamic_right = match right.clone() { + Pattern::Dynamic(pattern) => Some(pattern), Pattern::CodeSnippet(GritCodeSnippet { - dynamic_snippet: Some(r), + dynamic_snippet: Some(snippet), .. - }) => Some(r.clone()), - Pattern::Variable(v) => Some(DynamicPattern::Variable(*v)), + }) => Some(snippet), + Pattern::Variable(variable) => Some(DynamicPattern::Variable(variable)), _ => None, }; @@ -38,13 +38,13 @@ impl PrAccumulateCompiler { ) -> Result, CompileError> { let left = Pattern::Variable(VariableCompiler::from_node(&node.left()?, context)); let right = PatternCompiler::from_node_with_rhs(&node.right()?, context, true)?; - let dynamic_right = match &right { - Pattern::Dynamic(r) => Some(r.clone()), + let dynamic_right = match right.clone() { + Pattern::Dynamic(pattern) => Some(pattern), Pattern::CodeSnippet(GritCodeSnippet { - dynamic_snippet: Some(r), + dynamic_snippet: Some(snippet), .. - }) => Some(r.clone()), - Pattern::Variable(v) => Some(DynamicPattern::Variable(*v)), + }) => Some(snippet), + Pattern::Variable(variable) => Some(DynamicPattern::Variable(variable)), _ => None, }; diff --git a/crates/biome_grit_patterns/src/pattern_compiler/as_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/as_compiler.rs index 700ac2a23a73..a6ac4748e43c 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/as_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/as_compiler.rs @@ -37,7 +37,7 @@ impl AsCompiler { let pattern = PatternCompiler::from_node(&pattern, context)?; let variable = VariableCompiler::from_node(&variable, context); Ok(Where::new( - Pattern::Variable(variable), + Pattern::Variable(variable.clone()), Predicate::Match(Box::new(Match::new( Container::Variable(variable), Some(pattern), diff --git a/crates/biome_grit_patterns/src/pattern_compiler/auto_wrap.rs b/crates/biome_grit_patterns/src/pattern_compiler/auto_wrap.rs index 3a1420b2f154..e5aaa9e632b2 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/auto_wrap.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/auto_wrap.rs @@ -8,7 +8,6 @@ use grit_pattern_matcher::pattern::{ Where, }; use grit_util::FileRange; -use std::collections::BTreeMap; pub fn auto_wrap_pattern( pattern: Pattern, @@ -56,10 +55,7 @@ pub fn auto_wrap_pattern( } else { second_wrap }; - wrap_pattern_in_before_and_after_each_file( - third_wrap, - &context.compilation.pattern_definition_info, - )? + wrap_pattern_in_before_and_after_each_file(third_wrap, context)? } else { pattern }; @@ -79,10 +75,10 @@ fn is_sequential( Pattern::Where(w) => is_sequential(&w.pattern, pattern_definitions), Pattern::Maybe(m) => is_sequential(&m.pattern, pattern_definitions), Pattern::Rewrite(r) => is_sequential(&r.left, pattern_definitions), - Pattern::Bubble(b) => is_sequential(&b.pattern_def.pattern, pattern_definitions), + Pattern::Bubble(b) => is_sequential(b.pattern_def.pattern(), pattern_definitions), Pattern::Limit(l) => is_sequential(&l.pattern, pattern_definitions), Pattern::Call(call) => is_sequential( - &pattern_definitions[call.index].pattern, + pattern_definitions[call.index].pattern(), pattern_definitions, ), Pattern::AstNode(_) @@ -96,6 +92,7 @@ fn is_sequential( | Pattern::CallBuiltIn(_) | Pattern::CallFunction(_) | Pattern::CallForeignFunction(_) + | Pattern::CallbackPattern(_) | Pattern::Assignment(_) | Pattern::Accumulate(_) | Pattern::And(_) @@ -145,10 +142,10 @@ pub(crate) fn should_autowrap( Pattern::Where(w) => should_autowrap(&w.pattern, pattern_definitions), Pattern::Maybe(m) => should_autowrap(&m.pattern, pattern_definitions), Pattern::Rewrite(r) => should_autowrap(&r.left, pattern_definitions), - Pattern::Bubble(b) => should_autowrap(&b.pattern_def.pattern, pattern_definitions), + Pattern::Bubble(b) => should_autowrap(b.pattern_def.pattern(), pattern_definitions), Pattern::Limit(l) => should_autowrap(&l.pattern, pattern_definitions), Pattern::Call(call) => should_autowrap( - &pattern_definitions[call.index].pattern, + pattern_definitions[call.index].pattern(), pattern_definitions, ), Pattern::AstNode(_) @@ -161,6 +158,7 @@ pub(crate) fn should_autowrap( | Pattern::CallBuiltIn(_) | Pattern::CallFunction(_) | Pattern::CallForeignFunction(_) + | Pattern::CallbackPattern(_) | Pattern::Assignment(_) | Pattern::Accumulate(_) | Pattern::And(_) @@ -220,26 +218,26 @@ fn extract_limit_pattern( Pattern::Rewrite(Box::new(Rewrite::new(extracted.0, r.right, r.annotation))); (pattern, extracted.1) } - Pattern::Bubble(b) => { - let extracted = extract_limit_pattern(b.pattern_def.pattern, pattern_definitions); + Pattern::Bubble(bubble) => { + let extracted = + extract_limit_pattern(bubble.pattern_def.pattern().clone(), pattern_definitions); let pattern = Pattern::Bubble(Box::new(Bubble::new( PatternDefinition::new( - b.pattern_def.name.clone(), - b.pattern_def.scope, - b.pattern_def.params.clone(), - b.pattern_def.local_vars.clone(), + bubble.pattern_def.name.clone(), + bubble.pattern_def.try_scope().unwrap(), + bubble.pattern_def.params().clone(), extracted.0, ), - b.args.into_iter().flatten().collect(), + bubble.args.into_iter().flatten().collect(), ))); (pattern, extracted.1) } Pattern::Call(call) => { let (new_pattern, extracted_limit) = extract_limit_pattern( - pattern_definitions[call.index].pattern.clone(), + pattern_definitions[call.index].pattern().clone(), pattern_definitions, ); - pattern_definitions[call.index].pattern = new_pattern; + pattern_definitions[call.index].replace_pattern(new_pattern); (Pattern::Call(call), extracted_limit) } Pattern::AstNode(_) @@ -255,6 +253,7 @@ fn extract_limit_pattern( | Pattern::CallBuiltIn(_) | Pattern::CallFunction(_) | Pattern::CallForeignFunction(_) + | Pattern::CallbackPattern(_) | Pattern::Assignment(_) | Pattern::Accumulate(_) | Pattern::And(_) @@ -303,10 +302,10 @@ fn should_wrap_in_file( Pattern::Where(w) => should_wrap_in_file(&w.pattern, pattern_definitions), Pattern::Maybe(m) => should_wrap_in_file(&m.pattern, pattern_definitions), Pattern::Rewrite(r) => should_wrap_in_file(&r.left, pattern_definitions), - Pattern::Bubble(b) => should_wrap_in_file(&b.pattern_def.pattern, pattern_definitions), + Pattern::Bubble(b) => should_wrap_in_file(b.pattern_def.pattern(), pattern_definitions), Pattern::Limit(l) => should_wrap_in_file(&l.pattern, pattern_definitions), Pattern::Call(call) => should_wrap_in_file( - &pattern_definitions[call.index].pattern, + pattern_definitions[call.index].pattern(), pattern_definitions, ), Pattern::AstNode(_) @@ -319,6 +318,7 @@ fn should_wrap_in_file( | Pattern::CallBuiltIn(_) | Pattern::CallFunction(_) | Pattern::CallForeignFunction(_) + | Pattern::CallbackPattern(_) | Pattern::Assignment(_) | Pattern::Accumulate(_) | Pattern::And(_) @@ -368,7 +368,7 @@ fn wrap_pattern_in_range( let range = file_range.range.clone(); let range = Range::from(range); let range_match = Predicate::Match(Box::new(Match::new( - Container::Variable(var), + Container::Variable(var.clone()), Some(Pattern::Range(range)), ))); let file_match = Predicate::Match(Box::new(Match::new( @@ -389,7 +389,7 @@ fn wrap_pattern_in_range( Predicate::Or(Box::new(PrOr::new(predicates))), ))); let pattern = Pattern::Where(Box::new(Where::new( - Pattern::Variable(var), + Pattern::Variable(var.clone()), Predicate::Match(Box::new(Match::new( Container::Variable(var), Some(pattern), @@ -405,19 +405,14 @@ fn wrap_pattern_in_contains( ) -> Result, CompileError> { let var = context.variable_from_name(var_name); let pattern = Pattern::Where(Box::new(Where::new( - Pattern::Variable(var), + Pattern::Variable(var.clone()), Predicate::Match(Box::new(Match::new( Container::Variable(var), Some(pattern), ))), ))); - let pattern_definition = PatternDefinition::new( - "".to_string(), - context.scope_index, - vec![], - context.vars.values().copied().collect(), - pattern, - ); + let pattern_definition = + PatternDefinition::new("".to_string(), context.scope_index, vec![], pattern); let bubble = Pattern::Bubble(Box::new(Bubble::new(pattern_definition, vec![]))); Ok(Pattern::Contains(Box::new(Contains::new(bubble, None)))) } @@ -429,7 +424,7 @@ fn wrap_pattern_in_file(pattern: Pattern) -> Result( pattern: Pattern, - pattern_definition_info: &BTreeMap, + context: &mut NodeCompilationContext<'_>, ) -> Result, CompileError> { let before_each_file = "before_each_file"; let after_each_file = "after_each_file"; @@ -437,7 +432,7 @@ pub(crate) fn wrap_pattern_in_before_and_after_each_file( if let Some(DefinitionInfo { index, parameters: _, - }) = pattern_definition_info.get(before_each_file) + }) = context.get_pattern_definition(before_each_file) { all_steps.push(Pattern::Call(Box::new(Call::new(*index, vec![])))); } @@ -446,7 +441,7 @@ pub(crate) fn wrap_pattern_in_before_and_after_each_file( if let Some(DefinitionInfo { index, parameters: _, - }) = pattern_definition_info.get(after_each_file) + }) = context.get_pattern_definition(after_each_file) { all_steps.push(Pattern::Call(Box::new(Call::new(*index, vec![])))); } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/bubble_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/bubble_compiler.rs index ce99c62ec1af..6ef31068193f 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/bubble_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/bubble_compiler.rs @@ -48,13 +48,8 @@ impl BubbleCompiler { .map(|(name, range)| Ok(Pattern::Variable(context.register_variable(name, range)))) .collect::, CompileError>>()?; - let pattern_def = PatternDefinition::new( - "".to_owned(), - local_scope_index, - params, - local_vars.values().copied().collect(), - body, - ); + let pattern_def = + PatternDefinition::new("".to_owned(), local_scope_index, params, body); Ok(Bubble::new(pattern_def, args)) } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs index 4e44c08a87ed..8e36662a3fde 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs @@ -67,7 +67,7 @@ pub(super) fn call_pattern_from_node_with_name( let params = &built_in.params; Ok(Pattern::CallBuiltIn(Box::new(call_built_in_from_args( - args, params, index, lang, + args, params, index, lang, &name, )?))) } else if let Some(info) = context.compilation.function_definition_info.get(&name) { let args = match_args_to_params(&name, args, &collect_params(&info.parameters), lang)?; @@ -87,15 +87,13 @@ fn call_built_in_from_args( params: &[&str], index: usize, lang: &impl Language, + name: &str, ) -> Result, CompileError> { let mut pattern_params = Vec::with_capacity(args.len()); for param in params.iter() { - match args.remove(&(lang.metavariable_prefix().to_owned() + param)) { - Some(p) => pattern_params.push(Some(p)), - None => pattern_params.push(None), - } + pattern_params.push(args.remove(&(lang.metavariable_prefix().to_owned() + param))); } - Ok(CallBuiltIn::new(index, pattern_params)) + Ok(CallBuiltIn::new(index, name, pattern_params)) } pub(super) fn collect_params(parameters: &[(String, ByteRange)]) -> Vec { diff --git a/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs b/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs index 694809e0514e..0027ec556088 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs @@ -1,4 +1,4 @@ -use grit_pattern_matcher::pattern::VariableSourceLocations; +use grit_pattern_matcher::pattern::VariableSource; use grit_util::ByteRange; use crate::{ @@ -49,7 +49,7 @@ pub(crate) struct NodeCompilationContext<'a> { /// The outer vector can be index using `scope_index`, while the individual /// variables in a scope can be indexed using the indices stored in `vars` /// and `global_vars`. - pub vars_array: &'a mut Vec>, + pub vars_array: &'a mut Vec>, /// Index of the local scope. /// @@ -69,7 +69,7 @@ impl<'a> NodeCompilationContext<'a> { pub(crate) fn new( compilation_context: &'a CompilationContext, vars: &'a mut BTreeMap, - vars_array: &'a mut Vec>, + vars_array: &'a mut Vec>, global_vars: &'a mut BTreeMap, diagnostics: &'a mut Vec, ) -> Self { @@ -83,6 +83,10 @@ impl<'a> NodeCompilationContext<'a> { } } + pub(crate) fn get_pattern_definition(&self, name: &str) -> Option<&DefinitionInfo> { + self.compilation.pattern_definition_info.get(name) + } + pub(crate) fn log(&mut self, diagnostic: CompilerDiagnostic) { self.diagnostics.push(diagnostic); } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/log_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/log_compiler.rs index d17acb5e3d47..b65e4c67286e 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/log_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/log_compiler.rs @@ -17,13 +17,19 @@ impl LogCompiler { &context.compilation.lang, &Some(vec!["message".to_owned(), "variable".to_owned()]), )?; + + let var_name = named_args + .iter() + .find(|(name, _)| name == "variable") + .map(|(_, node)| node.to_string()); + let mut args = named_args_to_map(named_args, context)?; let message = args.remove("$message"); let variable = args.remove("$variable"); + let variable = variable.and_then(|pattern| match pattern { Pattern::Variable(variable) => { - let source_location = &context.vars_array[variable.scope][variable.index]; - Some(VariableInfo::new(source_location.name.clone(), variable)) + Some(VariableInfo::new(var_name.unwrap_or_default(), variable)) } _ => None, }); diff --git a/crates/biome_grit_patterns/src/pattern_compiler/not_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/not_compiler.rs index 9129f36f573e..dc5454778e79 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/not_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/not_compiler.rs @@ -5,7 +5,10 @@ use super::{ use crate::{diagnostics::CompilerDiagnostic, grit_context::GritQueryContext, CompileError}; use biome_grit_syntax::{GritPatternNot, GritPredicateNot}; use biome_rowan::AstNode; -use grit_pattern_matcher::pattern::{Not, Pattern, PatternOrPredicate, PrNot, Predicate}; +use grit_pattern_matcher::{ + context::StaticDefinitions, + pattern::{Not, Pattern, PatternOrPredicate, PrNot, Predicate}, +}; pub(crate) struct NotCompiler; @@ -15,7 +18,7 @@ impl NotCompiler { context: &mut NodeCompilationContext, ) -> Result, CompileError> { let pattern = PatternCompiler::from_node(&node.pattern()?, context)?; - if pattern.iter().any(|p| { + if pattern.iter(&StaticDefinitions::default()).any(|p| { matches!( p, PatternOrPredicate::Pattern(Pattern::Rewrite(_)) @@ -40,7 +43,7 @@ impl PrNotCompiler { context: &mut NodeCompilationContext, ) -> Result, CompileError> { let predicate = PredicateCompiler::from_node(&node.predicate()?, context)?; - if predicate.iter().any(|p| { + if predicate.iter(&StaticDefinitions::default()).any(|p| { matches!( p, PatternOrPredicate::Pattern(Pattern::Rewrite(_)) diff --git a/crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs index dba96d0d8384..7f9e0a324d07 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs @@ -32,13 +32,7 @@ impl PatternDefinitionCompiler { &mut context, )?)); - let pattern_def = PatternDefinition::new( - name.to_owned(), - scope_index, - params, - local_vars.values().copied().collect(), - body, - ); + let pattern_def = PatternDefinition::new(name.to_owned(), scope_index, params, body); Ok(pattern_def) } } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/snippet_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/snippet_compiler.rs index adf776c19a77..7dcdaffe0787 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/snippet_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/snippet_compiler.rs @@ -11,7 +11,7 @@ use grit_pattern_matcher::{ constants::GLOBAL_VARS_SCOPE_INDEX, pattern::{ is_reserved_metavariable, DynamicPattern, DynamicSnippet, DynamicSnippetPart, List, - Pattern, RegexLike, RegexPattern, Variable, + Pattern, RegexLike, RegexPattern, Variable, VariableSource, }, }; use grit_util::{traverse, Ast, AstNode, ByteRange, GritMetaValue, Language, Order, SnippetTree}; @@ -108,16 +108,18 @@ pub(crate) fn dynamic_snippet_from_source( source_range.start + byte_range.start + var.len(), ); if let Some(var) = context.vars.get(var.as_ref()) { - context.vars_array[context.scope_index][*var] - .locations - .insert(range); + if let VariableSource::Compiled { locations, .. } = + &mut context.vars_array[context.scope_index][*var] + { + locations.insert(range); + } parts.push(DynamicSnippetPart::Variable(Variable::new( context.scope_index, *var, ))); } else if let Some(var) = context.global_vars.get(var.as_ref()) { parts.push(DynamicSnippetPart::Variable(Variable::new( - GLOBAL_VARS_SCOPE_INDEX, + GLOBAL_VARS_SCOPE_INDEX.into(), *var, ))); } else if var.starts_with("$GLOBAL_") { @@ -812,8 +814,12 @@ mod tests { slot_index: 0, pattern: Variable( Variable { - scope: 0, - index: 0, + internal: Static( + VariableScope { + scope: 0, + index: 0, + }, + ), }, ), }, @@ -877,8 +883,12 @@ mod tests { slot_index: 0, pattern: Variable( Variable { - scope: 0, - index: 0, + internal: Static( + VariableScope { + scope: 0, + index: 0, + }, + ), }, ), }, @@ -980,8 +990,12 @@ mod tests { slot_index: 0, pattern: Variable( Variable { - scope: 0, - index: 0, + internal: Static( + VariableScope { + scope: 0, + index: 0, + }, + ), }, ), }, @@ -1009,8 +1023,12 @@ mod tests { slot_index: 0, pattern: Variable( Variable { - scope: 0, - index: 0, + internal: Static( + VariableScope { + scope: 0, + index: 0, + }, + ), }, ), }, @@ -1134,8 +1152,12 @@ mod tests { slot_index: 0, pattern: Variable( Variable { - scope: 0, - index: 0, + internal: Static( + VariableScope { + scope: 0, + index: 0, + }, + ), }, ), }, @@ -1199,8 +1221,12 @@ mod tests { slot_index: 0, pattern: Variable( Variable { - scope: 0, - index: 0, + internal: Static( + VariableScope { + scope: 0, + index: 0, + }, + ), }, ), }, diff --git a/crates/biome_grit_patterns/src/pattern_compiler/step_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/step_compiler.rs index 58deb8cb41b3..0a406d53e8b8 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/step_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/step_compiler.rs @@ -41,6 +41,7 @@ impl StepCompiler { | Pattern::CallBuiltIn(_) | Pattern::CallFunction(_) | Pattern::CallForeignFunction(_) + | Pattern::CallbackPattern(_) | Pattern::Assignment(_) | Pattern::Accumulate(_) | Pattern::Any(_) @@ -99,10 +100,7 @@ impl StepCompiler { } } } - let pattern = wrap_pattern_in_before_and_after_each_file( - pattern, - &context.compilation.pattern_definition_info, - )?; + let pattern = wrap_pattern_in_before_and_after_each_file(pattern, context)?; Ok(Step::new(pattern)) } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/variable_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/variable_compiler.rs index a353addcc6f1..3fa383c5cc36 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/variable_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/variable_compiler.rs @@ -3,7 +3,7 @@ use crate::util::TextRangeGritExt; use biome_grit_syntax::GritVariable; use biome_rowan::AstNode; use grit_pattern_matcher::constants::GLOBAL_VARS_SCOPE_INDEX; -use grit_pattern_matcher::pattern::{Variable, VariableSourceLocations}; +use grit_pattern_matcher::pattern::{Variable, VariableSource}; use grit_util::ByteRange; use std::collections::BTreeSet; use std::path::Path; @@ -61,7 +61,11 @@ impl<'a> NodeCompilationContext<'a> { if let Some(i) = vars.get(&name) { if let Some(FileLocation { range, .. }) = location { - vars_array[*scope_index][*i].locations.insert(range); + if let VariableSource::Compiled { locations, .. } = + &mut vars_array[*scope_index][*i] + { + locations.insert(range); + } } return Variable::new(*scope_index, *i); } @@ -69,15 +73,17 @@ impl<'a> NodeCompilationContext<'a> { if let Some(i) = global_vars.get(&name) { if let Some(FileLocation { path, range }) = location { if path.is_none() { - vars_array[GLOBAL_VARS_SCOPE_INDEX][*i] - .locations - .insert(range); + if let VariableSource::Compiled { locations, .. } = + &mut vars_array[GLOBAL_VARS_SCOPE_INDEX as usize][*i] + { + locations.insert(range); + } } } - return Variable::new(GLOBAL_VARS_SCOPE_INDEX, *i); + return Variable::new(GLOBAL_VARS_SCOPE_INDEX.into(), *i); } let (name_map, scope_index) = if name.starts_with("$GLOBAL_") { - (global_vars, GLOBAL_VARS_SCOPE_INDEX) + (global_vars, GLOBAL_VARS_SCOPE_INDEX.into()) } else { (vars, *scope_index) }; @@ -93,7 +99,7 @@ impl<'a> NodeCompilationContext<'a> { (BTreeSet::new(), None) }; - scope.push(VariableSourceLocations { + scope.push(VariableSource::Compiled { name, file: path .map(|p| p.to_string_lossy().to_string()) diff --git a/crates/biome_grit_patterns/src/variables.rs b/crates/biome_grit_patterns/src/variables.rs index aaf49ffa05d4..2c59e403ac52 100644 --- a/crates/biome_grit_patterns/src/variables.rs +++ b/crates/biome_grit_patterns/src/variables.rs @@ -1,7 +1,6 @@ use crate::grit_context::GritQueryContext; -use grit_pattern_matcher::pattern::{VariableContent, VariableSourceLocations}; +use grit_pattern_matcher::pattern::{VariableContent, VariableSource}; use grit_util::VariableBinding; -use im::{vector, Vector}; /// List of all variable locations in a query. /// @@ -10,10 +9,10 @@ use im::{vector, Vector}; /// variable, we track the separate locations (plural) where that variable /// occurs. #[derive(Clone, Debug, Default)] -pub struct VariableLocations(Vec>); +pub struct VariableLocations(Vec>); impl VariableLocations { - pub(crate) fn new(locations: Vec>) -> Self { + pub(crate) fn new(locations: Vec>) -> Self { Self(locations) } @@ -22,12 +21,14 @@ impl VariableLocations { let mut variables = Vec::new(); for (i, scope) in self.0.iter().enumerate() { for (j, var) in scope.iter().enumerate() { - if var.file.is_empty() { - let name = &var.name; + if let VariableSource::Compiled { + name, locations, .. + } = var + { variables.push(VariableBinding { name: name.to_owned(), scoped_name: format!("{i}_{j}_{name}"), - ranges: var.locations.iter().copied().collect(), + ranges: locations.iter().copied().collect(), }); } } @@ -50,9 +51,9 @@ impl<'a> VarRegistry<'a> { .0 .iter() .map(|scope| { - vector![scope + vec![scope .iter() - .map(|s| Box::new(VariableContent::new(s.name.clone()))) + .map(|s| Box::new(VariableContent::new(s.name().to_owned()))) .collect()] }) .collect(); @@ -61,8 +62,7 @@ impl<'a> VarRegistry<'a> { } } -pub(crate) type VarRegistryVector<'a> = - Vector>>>>; +pub(crate) type VarRegistryVector<'a> = Vec>>>>; impl<'a> From> for VarRegistryVector<'a> { fn from(value: VarRegistry<'a>) -> Self {