diff --git a/crates/core/src/binding.rs b/crates/core/src/binding.rs index 74c6d1f97..5c2d9fffa 100644 --- a/crates/core/src/binding.rs +++ b/crates/core/src/binding.rs @@ -80,16 +80,16 @@ pub enum Binding<'a> { impl PartialEq for Binding<'_> { fn eq(&self, other: &Self) -> bool { match (self, other) { - (Binding::Empty(_, _, _), Binding::Empty(_, _, _)) => true, - (Binding::Node(src1, n1), Binding::Node(src2, n2)) => { + (Self::Empty(_, _, _), Self::Empty(_, _, _)) => true, + (Self::Node(src1, n1), Self::Node(src2, n2)) => { n1.utf8_text(src1.as_bytes()) == n2.utf8_text(src2.as_bytes()) } - (Binding::String(src1, r1), Binding::String(src2, r2)) => { + (Self::String(src1, r1), Self::String(src2, r2)) => { src1[r1.start_byte as usize..r1.end_byte as usize] == src2[r2.start_byte as usize..r2.end_byte as usize] } - (Binding::List(_, n1, f1), Binding::List(_, n2, f2)) => n1 == n2 && f1 == f2, - (Binding::ConstantRef(c1), Binding::ConstantRef(c2)) => c1 == c2, + (Self::List(_, n1, f1), Self::List(_, n2, f2)) => n1 == n2 && f1 == f2, + (Self::ConstantRef(c1), Self::ConstantRef(c2)) => c1 == c2, _ => false, } } @@ -307,10 +307,22 @@ pub(crate) fn linearize_binding<'a>( } impl<'a> Binding<'a> { + pub(crate) fn from_constant(constant: &'a Constant) -> Self { + Self::ConstantRef(constant) + } + pub(crate) fn from_node(node: NodeWithSource<'a>) -> Self { Self::Node(node.source, node.node) } + pub(crate) fn from_path(path: &'a Path) -> Self { + Self::FileName(path) + } + + pub(crate) fn from_range(range: Range, source: &'a str) -> Self { + Self::String(source, range) + } + /// Returns the only node bound by this binding. /// /// This includes list bindings that only match a single child. @@ -339,8 +351,8 @@ impl<'a> Binding<'a> { pub fn get_sexp(&self) -> Option { match self { - Binding::Node(_, node) => Some(node.to_sexp().to_string()), - Binding::List(_, parent_node, field_id) => { + Self::Node(_, node) => Some(node.to_sexp().to_string()), + Self::List(_, parent_node, field_id) => { let mut cursor = parent_node.walk(); let mut children = parent_node.children_by_field_id(*field_id, &mut cursor); let mut result = String::new(); @@ -353,20 +365,17 @@ impl<'a> Binding<'a> { } Some(result) } - Binding::String(..) - | Binding::FileName(_) - | Binding::Empty(..) - | Binding::ConstantRef(_) => None, + Self::String(..) | Self::FileName(_) | Self::Empty(..) | Self::ConstantRef(_) => None, } } // todo implement for empty and empty list pub fn position(&self) -> Option { match self { - Binding::Empty(_, _, _) => None, - Binding::Node(_, node) => Some(Range::from(node.range())), - Binding::String(_, range) => Some(range.to_owned()), - Binding::List(_, parent_node, field_id) => { + Self::Empty(_, _, _) => None, + Self::Node(_, node) => Some(Range::from(node.range())), + Self::String(_, range) => Some(range.to_owned()), + Self::List(_, parent_node, field_id) => { let mut cursor = parent_node.walk(); let mut children = parent_node.children_by_field_id(*field_id, &mut cursor); @@ -408,8 +417,8 @@ impl<'a> Binding<'a> { } } } - Binding::FileName(_) => None, - Binding::ConstantRef(_) => None, + Self::FileName(_) => None, + Self::ConstantRef(_) => None, } } @@ -423,8 +432,8 @@ impl<'a> Binding<'a> { logs: &mut AnalysisLogs, ) -> Result> { let res: Result> = match self { - Binding::Empty(_, _, _) => Ok(Cow::Borrowed("")), - Binding::Node(source, node) => { + Self::Empty(_, _, _) => Ok(Cow::Borrowed("")), + Self::Node(source, node) => { let range = CodeRange::from_node(source, node); linearize_binding( language, @@ -440,11 +449,11 @@ impl<'a> Binding<'a> { } // can't linearize until we update source to point to the entire file // otherwise file file pointers won't match - Binding::String(s, r) => Ok(Cow::Owned( + Self::String(s, r) => Ok(Cow::Owned( s[r.start_byte as usize..r.end_byte as usize].into(), )), - Binding::FileName(s) => Ok(Cow::Owned(s.to_string_lossy().into())), - Binding::List(source, _parent_node, _field_id) => { + Self::FileName(s) => Ok(Cow::Owned(s.to_string_lossy().into())), + Self::List(source, _parent_node, _field_id) => { if let Some(pos) = self.position() { let range = CodeRange::new(pos.start_byte, pos.end_byte, source); linearize_binding( @@ -462,37 +471,37 @@ impl<'a> Binding<'a> { Ok("".into()) } } - Binding::ConstantRef(c) => Ok(Cow::Owned(c.to_string())), + Self::ConstantRef(c) => Ok(Cow::Owned(c.to_string())), }; res } pub fn text(&self) -> String { match self { - Binding::Empty(_, _, _) => "".to_string(), - Binding::Node(source, node) => { + Self::Empty(_, _, _) => "".to_string(), + Self::Node(source, node) => { NodeWithSource::new(node.clone(), source).text().to_string() } - Binding::String(s, r) => s[r.start_byte as usize..r.end_byte as usize].into(), - Binding::FileName(s) => s.to_string_lossy().into(), - Binding::List(source, _, _) => { + Self::String(s, r) => s[r.start_byte as usize..r.end_byte as usize].into(), + Self::FileName(s) => s.to_string_lossy().into(), + Self::List(source, _, _) => { if let Some(pos) = self.position() { source[pos.start_byte as usize..pos.end_byte as usize].to_string() } else { "".to_string() } } - Binding::ConstantRef(c) => c.to_string(), + Self::ConstantRef(c) => c.to_string(), } } pub fn source(&self) -> Option<&'a str> { match self { - Binding::Empty(source, _, _) => Some(source), - Binding::Node(source, _) => Some(source), - Binding::String(source, _) => Some(source), - Binding::List(source, _, _) => Some(source), - Binding::FileName(..) | Binding::ConstantRef(..) => None, + Self::Empty(source, _, _) => Some(source), + Self::Node(source, _) => Some(source), + Self::String(source, _) => Some(source), + Self::List(source, _, _) => Some(source), + Self::FileName(..) | Self::ConstantRef(..) => None, } } diff --git a/crates/core/src/pattern/after.rs b/crates/core/src/pattern/after.rs index 698826ef6..77bb4c9ee 100644 --- a/crates/core/src/pattern/after.rs +++ b/crates/core/src/pattern/after.rs @@ -5,12 +5,11 @@ use super::{ variable::VariableSourceLocations, Node, State, }; -use crate::{binding::Binding, context::Context, resolve}; use crate::{binding::Constant, errors::debug}; +use crate::{context::Context, resolve}; use anyhow::{anyhow, bail, Result}; use core::fmt::Debug; use grit_util::AstNode; -use im::vector; use marzano_util::analysis_logs::AnalysisLogs; use std::collections::BTreeMap; @@ -61,7 +60,7 @@ impl After { }; if let Some(next) = node.next_non_trivia_node() { - Ok(ResolvedPattern::Binding(vector![Binding::from_node(next)])) + Ok(ResolvedPattern::from_node(next)) } else { debug( logs, diff --git a/crates/core/src/pattern/ast_node.rs b/crates/core/src/pattern/ast_node.rs index c0804e913..b1f073585 100644 --- a/crates/core/src/pattern/ast_node.rs +++ b/crates/core/src/pattern/ast_node.rs @@ -7,7 +7,7 @@ use super::{ variable::VariableSourceLocations, State, }; -use crate::{binding::Binding, context::Context, resolve}; +use crate::{context::Context, resolve}; use anyhow::{anyhow, Result}; use itertools::Itertools; use marzano_language::language::{FieldId, Language, SortId}; @@ -163,12 +163,7 @@ impl Matcher for ASTNode { return Ok(false); }; if binding.is_list() { - return self.execute( - &ResolvedPattern::from_binding(Binding::from_node(node)), - init_state, - context, - logs, - ); + return self.execute(&ResolvedPattern::from_node(node), init_state, context, logs); } let NodeWithSource { node, source } = node; @@ -181,10 +176,9 @@ impl Matcher for ASTNode { if context.language().is_comment(self.sort) { let content = context.language().comment_text(&node, source); let content = resolve!(content); - let content = Binding::String(source, content.1); return self.args[0].2.execute( - &ResolvedPattern::from_binding(content), + &ResolvedPattern::from_range(content.1, source), init_state, context, logs, diff --git a/crates/core/src/pattern/before.rs b/crates/core/src/pattern/before.rs index 0b5c682e1..65231249b 100644 --- a/crates/core/src/pattern/before.rs +++ b/crates/core/src/pattern/before.rs @@ -5,12 +5,11 @@ use super::{ variable::VariableSourceLocations, Node, State, }; -use crate::{binding::Binding, context::Context, resolve}; use crate::{binding::Constant, errors::debug}; +use crate::{context::Context, resolve}; use anyhow::{anyhow, bail, Result}; use core::fmt::Debug; use grit_util::AstNode; -use im::vector; use marzano_util::analysis_logs::AnalysisLogs; use std::collections::BTreeMap; @@ -61,7 +60,7 @@ impl Before { }; if let Some(prev) = node.previous_non_trivia_node() { - Ok(ResolvedPattern::Binding(vector![Binding::from_node(prev)])) + Ok(ResolvedPattern::from_node(prev)) } else { debug( logs, diff --git a/crates/core/src/pattern/list_index.rs b/crates/core/src/pattern/list_index.rs index e04fe9e9b..4b1915c34 100644 --- a/crates/core/src/pattern/list_index.rs +++ b/crates/core/src/pattern/list_index.rs @@ -12,8 +12,10 @@ use crate::binding::{Binding, Constant}; use crate::context::Context; use crate::resolve_opt; use anyhow::{anyhow, bail, Result}; -use im::vector; -use marzano_util::{analysis_logs::AnalysisLogs, tree_sitter_util::named_children_by_field_id}; +use marzano_util::{ + analysis_logs::AnalysisLogs, node_with_source::NodeWithSource, + tree_sitter_util::named_children_by_field_id, +}; use std::collections::BTreeMap; use tree_sitter::Node; @@ -138,9 +140,9 @@ impl ListIndex { let mut list = named_children_by_field_id(node, &mut cursor, *field); let index = resolve_opt!(to_unsigned(index, len)); return Ok(list.nth(index).map(|n| { - PatternOrResolved::ResolvedBinding(ResolvedPattern::Binding(vector![ - Binding::Node(src, n) - ])) + PatternOrResolved::ResolvedBinding(ResolvedPattern::from_node( + NodeWithSource::new(n, src), + )) })); } bail!("left side of a listIndex must be a list") diff --git a/crates/core/src/pattern/or.rs b/crates/core/src/pattern/or.rs index d7a43a4ba..637a608f1 100644 --- a/crates/core/src/pattern/or.rs +++ b/crates/core/src/pattern/or.rs @@ -74,10 +74,10 @@ impl Matcher for Or { if let ResolvedPattern::Binding(binding_vector) = &binding { for p in self.patterns.iter() { // filter out pattern which cannot match because of a mismatched node type - if let (Binding::Node(_src, binding_node), Pattern::ASTNode(node_pattern)) = - (binding_vector.last().unwrap(), p) + if let (Some(binding_node), Pattern::ASTNode(node_pattern)) = + (binding_vector.last().and_then(Binding::as_node), p) { - if node_pattern.sort != binding_node.kind_id() { + if node_pattern.sort != binding_node.node.kind_id() { continue; } } diff --git a/crates/core/src/pattern/regex.rs b/crates/core/src/pattern/regex.rs index 9d15fee43..9c905a1f4 100644 --- a/crates/core/src/pattern/regex.rs +++ b/crates/core/src/pattern/regex.rs @@ -6,10 +6,9 @@ use super::{ variable::{Variable, VariableSourceLocations}, State, }; -use crate::{binding::Binding, context::Context}; +use crate::context::Context; use anyhow::{anyhow, bail, Result}; use core::fmt::Debug; -use im::vector; use marzano_language::{language::Language, target_language::TargetLanguage}; use marzano_util::analysis_logs::{AnalysisLogBuilder, AnalysisLogs}; use marzano_util::position::Range; @@ -201,7 +200,7 @@ impl RegexPattern { // have a Range for String bindings? position.end_byte = position.start_byte + range.end as u32; position.start_byte += range.start as u32; - ResolvedPattern::Binding(vector![Binding::String(source, position)]) + ResolvedPattern::from_range(position, source) } else { ResolvedPattern::from_string(value.to_string()) } diff --git a/crates/core/src/pattern/resolved_pattern.rs b/crates/core/src/pattern/resolved_pattern.rs index 5fdc9ca52..c5435cd92 100644 --- a/crates/core/src/pattern/resolved_pattern.rs +++ b/crates/core/src/pattern/resolved_pattern.rs @@ -23,6 +23,7 @@ use marzano_util::{ use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, + path::Path, }; use tree_sitter::Node; @@ -56,9 +57,7 @@ impl<'a> File<'a> { pub(crate) fn name(&self, files: &FileRegistry<'a>) -> ResolvedPattern<'a> { match self { File::Resolved(resolved) => resolved.name.clone(), - File::Ptr(ptr) => { - ResolvedPattern::Binding(vector![Binding::FileName(&files.get_file(*ptr).name)]) - } + File::Ptr(ptr) => ResolvedPattern::from_path(&files.get_file(*ptr).name), } } @@ -69,9 +68,9 @@ impl<'a> File<'a> { let absolute_path = absolutize(name.as_ref())?; Ok(ResolvedPattern::Constant(Constant::String(absolute_path))) } - File::Ptr(ptr) => Ok(ResolvedPattern::Binding(vector![Binding::FileName( - &files.get_file(*ptr).absolute_path - )])), + File::Ptr(ptr) => Ok(ResolvedPattern::from_path( + &files.get_file(*ptr).absolute_path, + )), } } @@ -81,7 +80,7 @@ impl<'a> File<'a> { File::Ptr(ptr) => { let file = &files.get_file(*ptr); let range = file.tree.root_node().range().into(); - ResolvedPattern::Binding(vector![Binding::String(&file.source, range)]) + ResolvedPattern::from_range(range, &file.source) } } } @@ -92,7 +91,7 @@ impl<'a> File<'a> { File::Ptr(ptr) => { let file = &files.get_file(*ptr); let node = file.tree.root_node(); - ResolvedPattern::Binding(vector![Binding::Node(&file.source, node)]) + ResolvedPattern::from_node(NodeWithSource::new(node, &file.source)) } } } @@ -175,7 +174,7 @@ impl<'a> JoinFn<'a> { .children_by_field_id(*field, &mut parent_node.walk()) .filter(|child| child.is_named()) .map(|p| { - ResolvedPattern::Binding(vector![Binding::Node(src, p)]).linearized_text( + ResolvedPattern::from_node(NodeWithSource::new(p, src)).linearized_text( language, effects, files, @@ -205,7 +204,7 @@ impl<'a> JoinFn<'a> { }) => parent_node .children_by_field_id(*field, &mut parent_node.walk()) .filter(|child| child.is_named()) - .map(|p| ResolvedPattern::Binding(vector![Binding::Node(src, p)]).text(state)) + .map(|p| ResolvedPattern::from_node(NodeWithSource::new(p, src)).text(state)) .collect::>>()? .join(&self.separator) .into(), @@ -477,19 +476,27 @@ impl<'a> ResolvedPattern<'a> { } pub fn from_constant(constant: &'a Constant) -> Self { - Self::Binding(vector![Binding::ConstantRef(constant)]) + Self::from_binding(Binding::from_constant(constant)) } pub(crate) fn from_node(node: NodeWithSource<'a>) -> Self { - Self::Binding(vector![Binding::Node(node.source, node.node)]) + Self::from_binding(Binding::from_node(node)) } pub(crate) fn from_list(src: &'a str, node: Node<'a>, field_id: FieldId) -> Self { - Self::Binding(vector![Binding::List(src, node, field_id)]) + Self::from_binding(Binding::List(src, node, field_id)) } pub(crate) fn empty_field(src: &'a str, node: Node<'a>, field_id: FieldId) -> Self { - Self::Binding(vector![Binding::Empty(src, node, field_id)]) + Self::from_binding(Binding::Empty(src, node, field_id)) + } + + pub(crate) fn from_path(path: &'a Path) -> Self { + Self::from_binding(Binding::from_path(path)) + } + + pub(crate) fn from_range(range: Range, src: &'a str) -> Self { + Self::from_binding(Binding::from_range(range, src)) } pub fn from_string(string: String) -> Self { diff --git a/crates/core/src/text_unparser.rs b/crates/core/src/text_unparser.rs index ac5aeb9bf..dbeba20a0 100644 --- a/crates/core/src/text_unparser.rs +++ b/crates/core/src/text_unparser.rs @@ -1,4 +1,4 @@ -use crate::binding::{linearize_binding, Binding}; +use crate::binding::linearize_binding; use crate::pattern::resolved_pattern::CodeRange; use crate::pattern::state::FileRegistry; use crate::pattern::Effect; @@ -47,8 +47,8 @@ pub(crate) fn apply_effects<'a>( logs, )?; for effect in effects.iter() { - if let Binding::FileName(c) = effect.binding { - if std::ptr::eq(c, the_filename) { + if let Some(filename) = effect.binding.as_filename() { + if std::ptr::eq(filename, the_filename) { let snippet = effect .pattern .linearized_text(language, &effects, files, &mut memo, false, logs)?;