diff --git a/Cargo.lock b/Cargo.lock index 8aebc8b3f..89444a795 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1960,6 +1960,7 @@ dependencies = [ "anyhow", "elsa", "embeddings", + "futures", "getrandom", "grit-util", "im", diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index ad1821c07..d56f5fd11 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -35,6 +35,7 @@ path-absolutize = { version = "3.1.1", optional = false, features = [ "use_unix_paths_on_wasm", ] } getrandom = { version = "0.2.11", optional = true } +futures = "0.3.30" [dev-dependencies] similar = "2.2.1" diff --git a/crates/core/src/context.rs b/crates/core/src/context.rs index 7cdb3f7dd..08d3b5a43 100644 --- a/crates/core/src/context.rs +++ b/crates/core/src/context.rs @@ -22,7 +22,7 @@ pub trait Context { fn ignore_limit_pattern(&self) -> bool; - fn call_built_in<'a>( + async fn call_built_in<'a>( &self, call: &'a CallBuiltIn, context: &'a Self, diff --git a/crates/core/src/pattern.rs b/crates/core/src/pattern.rs index 64e324a1e..3c3356db5 100644 --- a/crates/core/src/pattern.rs +++ b/crates/core/src/pattern.rs @@ -454,7 +454,7 @@ impl Problem { }) } - fn execute_and_send( + async fn execute_and_send( &self, tx: &Sender>, files: &[impl TryIntoInputFile + FileName], @@ -463,7 +463,7 @@ impl Problem { context: &ExecutionContext, mut done_files: Vec, ) { - let mut outputs = match self.execute(binding, owned_files, context) { + let mut outputs = match self.execute(binding, owned_files, context).await { Result::Err(err) => files .iter() .map(|file| { @@ -653,7 +653,7 @@ impl Problem { } } - fn execute( + async fn execute( &self, binding: FilePattern, owned_files: &FileOwners, @@ -696,7 +696,8 @@ impl Problem { let binding = binding.into(); if self .pattern - .execute(&binding, &mut state, &context, &mut user_logs)? + .execute(&binding, &mut state, &context, &mut user_logs) + .await? { for file in state.files.files() { if let Some(result) = MatchResult::file_to_match_result(file, &self.language)? { @@ -839,14 +840,14 @@ impl<'a> Context for MarzanoContext<'a> { self.runtime.ignore_limit_pattern } - fn call_built_in<'b>( + async fn call_built_in<'b>( &self, call: &'b CallBuiltIn, context: &'b Self, state: &mut State<'b>, logs: &mut AnalysisLogs, ) -> Result> { - self.built_ins.call(call, context, state, logs) + self.built_ins.call(call, context, state, logs).await } #[cfg(all( diff --git a/crates/core/src/pattern/accessor.rs b/crates/core/src/pattern/accessor.rs index c3d4d32ce..5312b7134 100644 --- a/crates/core/src/pattern/accessor.rs +++ b/crates/core/src/pattern/accessor.rs @@ -167,7 +167,7 @@ impl Name for Accessor { } impl Matcher for Accessor { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -181,7 +181,7 @@ impl Matcher for Accessor { Some(PatternOrResolved::ResolvedBinding(r)) => { execute_resolved_with_binding(&r, binding, state) } - Some(PatternOrResolved::Pattern(p)) => p.execute(binding, state, context, logs), + Some(PatternOrResolved::Pattern(p)) => p.execute(binding, state, context, logs).await, None => Ok( matches!(binding, ResolvedPattern::Constant(Constant::Boolean(false))) || binding.matches_undefined(), diff --git a/crates/core/src/pattern/accumulate.rs b/crates/core/src/pattern/accumulate.rs index a4a590faa..bda4e4686 100644 --- a/crates/core/src/pattern/accumulate.rs +++ b/crates/core/src/pattern/accumulate.rs @@ -139,7 +139,7 @@ impl Name for Accumulate { } impl Matcher for Accumulate { - fn execute<'a>( + async fn execute<'a>( &'a self, context_node: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -148,7 +148,7 @@ impl Matcher for Accumulate { ) -> Result { if let Pattern::Variable(var) = &self.left { let var = state.trace_var(var); - let append = ResolvedPattern::from_pattern(&self.right, state, context, logs)?; + let append = ResolvedPattern::from_pattern(&self.right, state, context, logs).await?; if let Some(base) = state.bindings[var.scope].back_mut().unwrap()[var.index] .value .as_mut() @@ -162,7 +162,11 @@ impl Matcher for Accumulate { ) } } else { - let resolved = if !self.left.execute(context_node, state, context, logs)? { + let resolved = if !self + .left + .execute(context_node, state, context, logs) + .await? + { return Ok(false); } else { Cow::Borrowed(context_node) @@ -197,7 +201,7 @@ impl Matcher for Accumulate { } }; let mut replacement: ResolvedPattern<'_> = - ResolvedPattern::from_dynamic_pattern(dynamic_right, state, context, logs)?; + ResolvedPattern::from_dynamic_pattern(dynamic_right, state, context, logs).await?; let effects: Result> = bindings .iter() .map(|b| { @@ -218,7 +222,7 @@ impl Matcher for Accumulate { } impl Evaluator for Accumulate { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -226,7 +230,7 @@ impl Evaluator for Accumulate { ) -> Result { if let Pattern::Variable(var) = &self.left { let var = state.trace_var(var); - let append = ResolvedPattern::from_pattern(&self.right, state, context, logs)?; + let append = ResolvedPattern::from_pattern(&self.right, state, context, logs).await?; if let Some(base) = state.bindings[var.scope].back_mut().unwrap()[var.index] .value .as_mut() diff --git a/crates/core/src/pattern/add.rs b/crates/core/src/pattern/add.rs index f3ba26a60..4141ca77d 100644 --- a/crates/core/src/pattern/add.rs +++ b/crates/core/src/pattern/add.rs @@ -63,24 +63,24 @@ impl Add { Ok(Self::new(left, right)) } - pub(crate) fn call<'a>( + pub(crate) async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let res = self.evaluate(state, context, logs)?; + let res = self.evaluate(state, context, logs).await?; Ok(ResolvedPattern::Constant(Constant::Float(res))) } - fn evaluate<'a>( + async fn evaluate<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let lhs = self.lhs.float(state, context, logs)?; - let rhs = self.rhs.float(state, context, logs)?; + let lhs = self.lhs.float(state, context, logs).await?; + let rhs = self.rhs.float(state, context, logs).await?; let res = lhs + rhs; Ok(res) } @@ -93,7 +93,7 @@ impl Name for Add { } impl Matcher for Add { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -102,7 +102,7 @@ impl Matcher for Add { ) -> Result { let binding_text = binding.text(&state.files)?; let binding_int = binding_text.parse::()?; - let target = self.evaluate(state, context, logs)?; + let target = self.evaluate(state, context, logs).await?; Ok(binding_int == target) } } diff --git a/crates/core/src/pattern/after.rs b/crates/core/src/pattern/after.rs index 644d498a9..aeffc9399 100644 --- a/crates/core/src/pattern/after.rs +++ b/crates/core/src/pattern/after.rs @@ -48,13 +48,13 @@ impl After { Ok(Self::new(pattern)) } - pub(crate) fn next_pattern<'a>( + pub(crate) async fn next_pattern<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let binding = pattern_to_binding(&self.after, state, context, logs)?; + let binding = pattern_to_binding(&self.after, state, context, logs).await?; let Some(node) = binding.as_node() else { bail!("cannot get the node after this binding") }; @@ -79,7 +79,7 @@ impl Name for After { } impl Matcher for After { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -101,12 +101,16 @@ impl Matcher for After { return Ok(true); }; let prev_node = resolve!(node.previous_named_node()); - if !self.after.execute( - &ResolvedPattern::from_node(prev_node), - &mut cur_state, - context, - logs, - )? { + if !self + .after + .execute( + &ResolvedPattern::from_node(prev_node), + &mut cur_state, + context, + logs, + ) + .await? + { return Ok(false); } *init_state = cur_state; diff --git a/crates/core/src/pattern/and.rs b/crates/core/src/pattern/and.rs index 44b15c939..bf574dc47 100644 --- a/crates/core/src/pattern/and.rs +++ b/crates/core/src/pattern/and.rs @@ -68,7 +68,7 @@ impl Name for And { } impl Matcher for And { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -76,7 +76,7 @@ impl Matcher for And { logs: &mut AnalysisLogs, ) -> Result { for p in self.patterns.iter() { - if !p.execute(binding, state, context, logs)? { + if !p.execute(binding, state, context, logs).await? { return Ok(false); }; } @@ -132,14 +132,14 @@ impl Name for PrAnd { } impl Evaluator for PrAnd { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { for p in self.predicates.iter() { - let res = p.execute_func(state, context, logs)?; + let res = p.execute_func(state, context, logs).await?; match res.predicator { true => {} false => return Ok(res), diff --git a/crates/core/src/pattern/any.rs b/crates/core/src/pattern/any.rs index 73fa7d0e1..a349b13d9 100644 --- a/crates/core/src/pattern/any.rs +++ b/crates/core/src/pattern/any.rs @@ -68,7 +68,7 @@ impl Matcher for Any { // apply all successful updates to the state // must have at least one successful match // return soft and failed on failure - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -79,7 +79,10 @@ impl Matcher for Any { let mut cur_state = init_state.clone(); for pattern in &self.patterns { let state = cur_state.clone(); - if pattern.execute(binding, &mut cur_state, context, logs)? { + if pattern + .execute(binding, &mut cur_state, context, logs) + .await? + { matched = true; } else { cur_state = state; @@ -143,7 +146,7 @@ impl Name for PrAny { } impl Evaluator for PrAny { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, init_state: &mut State<'a>, context: &'a impl Context, @@ -154,7 +157,8 @@ impl Evaluator for PrAny { for predicate in &self.predicates { let state = cur_state.clone(); if predicate - .execute_func(&mut cur_state, context, logs)? + .execute_func(&mut cur_state, context, logs) + .await? .predicator { matched = true; diff --git a/crates/core/src/pattern/assignment.rs b/crates/core/src/pattern/assignment.rs index f9e4c2691..e0ce7cb28 100644 --- a/crates/core/src/pattern/assignment.rs +++ b/crates/core/src/pattern/assignment.rs @@ -75,28 +75,28 @@ impl Name for Assignment { } impl Matcher for Assignment { - fn execute<'a>( + async fn execute<'a>( &'a self, _context_node: &ResolvedPattern<'a>, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let resolved = ResolvedPattern::from_pattern(&self.pattern, state, context, logs)?; + let resolved = ResolvedPattern::from_pattern(&self.pattern, state, context, logs).await?; self.container.set_resolved(state, resolved)?; Ok(true) } } impl Evaluator for Assignment { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { let resolved: ResolvedPattern<'_> = - ResolvedPattern::from_pattern(&self.pattern, state, context, logs)?; + ResolvedPattern::from_pattern(&self.pattern, state, context, logs).await?; self.container.set_resolved(state, resolved)?; Ok(FuncEvaluation { predicator: true, diff --git a/crates/core/src/pattern/ast_node.rs b/crates/core/src/pattern/ast_node.rs index b1f073585..89786f888 100644 --- a/crates/core/src/pattern/ast_node.rs +++ b/crates/core/src/pattern/ast_node.rs @@ -147,7 +147,7 @@ impl Name for ASTNode { } impl Matcher for ASTNode { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -163,7 +163,13 @@ impl Matcher for ASTNode { return Ok(false); }; if binding.is_list() { - return self.execute(&ResolvedPattern::from_node(node), init_state, context, logs); + return Box::pin(self.execute( + &ResolvedPattern::from_node(node), + init_state, + context, + logs, + )) + .await; } let NodeWithSource { node, source } = node; @@ -177,38 +183,42 @@ impl Matcher for ASTNode { let content = context.language().comment_text(&node, source); let content = resolve!(content); - return self.args[0].2.execute( + return Box::pin(self.args[0].2.execute( &ResolvedPattern::from_range(content.1, source), init_state, context, logs, - ); + )) + .await; } let mut running_state = init_state.clone(); for (field_id, is_list, pattern) in &self.args { let mut cur_state = running_state.clone(); let res = if *is_list { - pattern.execute( + Box::pin(pattern.execute( &ResolvedPattern::from_list(source, node.clone(), *field_id), &mut cur_state, context, logs, - ) + )) + .await } else if let Some(child) = node.child_by_field_id(*field_id) { - pattern.execute( + Box::pin(pattern.execute( &ResolvedPattern::from_node(NodeWithSource::new(child, source)), &mut cur_state, context, logs, - ) + )) + .await } else { - pattern.execute( + Box::pin(pattern.execute( &ResolvedPattern::empty_field(source, node.clone(), *field_id), &mut cur_state, context, logs, - ) + )) + .await }; if res? { running_state = cur_state; diff --git a/crates/core/src/pattern/before.rs b/crates/core/src/pattern/before.rs index b446651c7..41ae061f8 100644 --- a/crates/core/src/pattern/before.rs +++ b/crates/core/src/pattern/before.rs @@ -48,13 +48,13 @@ impl Before { Ok(Self::new(pattern)) } - pub(crate) fn prev_pattern<'a>( + pub(crate) async fn prev_pattern<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let binding = pattern_to_binding(&self.before, state, context, logs)?; + let binding = pattern_to_binding(&self.before, state, context, logs).await?; let Some(node) = binding.as_node() else { bail!("cannot get the node before this binding") }; @@ -79,7 +79,7 @@ impl Name for Before { } impl Matcher for Before { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -101,12 +101,16 @@ impl Matcher for Before { return Ok(true); }; let next_node = resolve!(node.next_named_node()); - if !self.before.execute( - &ResolvedPattern::from_node(next_node), - &mut cur_state, - context, - logs, - )? { + if !self + .before + .execute( + &ResolvedPattern::from_node(next_node), + &mut cur_state, + context, + logs, + ) + .await? + { return Ok(false); } *init_state = cur_state; diff --git a/crates/core/src/pattern/boolean_constant.rs b/crates/core/src/pattern/boolean_constant.rs index c79d26352..8ed284331 100644 --- a/crates/core/src/pattern/boolean_constant.rs +++ b/crates/core/src/pattern/boolean_constant.rs @@ -36,7 +36,7 @@ impl Name for BooleanConstant { } impl Matcher for BooleanConstant { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, diff --git a/crates/core/src/pattern/bubble.rs b/crates/core/src/pattern/bubble.rs index 914224167..ad5c5e593 100644 --- a/crates/core/src/pattern/bubble.rs +++ b/crates/core/src/pattern/bubble.rs @@ -113,7 +113,7 @@ impl Name for Bubble { } impl Matcher for Bubble { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -122,5 +122,6 @@ impl Matcher for Bubble { ) -> Result { self.pattern_def .call(state, binding, context, logs, &self.args) + .await } } diff --git a/crates/core/src/pattern/built_in_functions.rs b/crates/core/src/pattern/built_in_functions.rs index eac0a3a35..9815f0b1d 100644 --- a/crates/core/src/pattern/built_in_functions.rs +++ b/crates/core/src/pattern/built_in_functions.rs @@ -1,4 +1,5 @@ use crate::{binding::Constant, context::Context}; +use futures::Future; use itertools::Itertools; use marzano_util::analysis_logs::AnalysisLogs; use rand::prelude::SliceRandom; @@ -21,7 +22,7 @@ use im::vector; use im::Vector; use marzano_language::language::Language; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, pin::Pin}; #[derive(Debug, Clone)] pub struct CallBuiltIn { @@ -53,13 +54,13 @@ impl CallBuiltIn { } impl GritCall for CallBuiltIn { - fn call<'a>( + async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - context.call_built_in(self, context, state, logs) + context.call_built_in(self, context, state, logs).await } } @@ -73,13 +74,33 @@ impl Name for CallBuiltIn { // eg. capitalize returns an owned string_constant pattern, but unique would return a borrowed // value. +// type F = dyn for<'a, 'b, 'c> Fn( +// &'a [std::option::Option], +// &'a MarzanoContext<'a>, +// &'b mut State<'a>, +// &'c mut AnalysisLogs, +// ) -> Pin< +// Box<(dyn futures::Future, anyhow::Error>>)>, +// > + Send +// + Sync; + +// type F = dyn for<'a> Fn( +// &'a [Option], +// &'a MarzanoContext<'a>, +// &mut State<'a>, +// &mut AnalysisLogs, +// ) -> (impl Future, Error>>) +// + Send +// + Sync; + type F = dyn for<'a> Fn( &'a [Option], &'a MarzanoContext<'a>, &mut State<'a>, &mut AnalysisLogs, - ) -> Result> - + Send + ) -> Pin< + Box<(dyn futures::Future, anyhow::Error>>)>, + > + Send + Sync; pub struct BuiltInFunction { @@ -89,14 +110,14 @@ pub struct BuiltInFunction { } impl BuiltInFunction { - fn call<'a>( + async fn call<'a>( &self, args: &'a [Option], context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, ) -> Result> { - (self.func)(args, context, state, logs) + (self.func)(args, context, state, logs).await } pub fn new(name: &'static str, params: Vec<&'static str>, func: Box) -> Self { @@ -117,14 +138,16 @@ impl std::fmt::Debug for BuiltInFunction { pub struct BuiltIns(Vec); impl BuiltIns { - pub(crate) fn call<'a>( + pub(crate) async fn call<'a>( &self, call: &'a CallBuiltIn, context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, ) -> Result> { - self.0[call.index].call(&call.args, context, state, logs) + self.0[call.index] + .call(&call.args, context, state, logs) + .await } pub fn extend_builtins(&mut self, other: BuiltIns) -> Result<()> { @@ -178,24 +201,27 @@ impl From> for BuiltIns { } } +// Pin, anyhow::Error>>)>> /// Turn an arbitrary path into a resolved and normalized absolute path fn resolve_path_fn<'a>( args: &'a [Option], context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; - let current_file = get_absolute_file_name(state)?; - let target_path = match &args[0] { - Some(resolved_pattern) => resolved_pattern.text(&state.files)?, - None => return Err(anyhow!("No path argument provided for resolve function")), - }; + let current_file = get_absolute_file_name(state)?; + let target_path = match &args[0] { + Some(resolved_pattern) => resolved_pattern.text(&state.files)?, + None => return Err(anyhow!("No path argument provided for resolve function")), + }; - let resolved_path = resolve(target_path, current_file.into())?; + let resolved_path = resolve(target_path, current_file.into())?; - Ok(ResolvedPattern::from_string(resolved_path)) + Ok(ResolvedPattern::from_string(resolved_path)) + }) } fn capitalize(s: &str) -> String { @@ -211,14 +237,16 @@ fn capitalize_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let s = match &args[0] { - Some(resolved_pattern) => resolved_pattern.text(&state.files)?, - None => return Err(anyhow!("No argument provided for capitalize function")), - }; - Ok(ResolvedPattern::from_string(capitalize(&s))) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let s = match &args[0] { + Some(resolved_pattern) => resolved_pattern.text(&state.files)?, + None => return Err(anyhow!("No argument provided for capitalize function")), + }; + Ok(ResolvedPattern::from_string(capitalize(&s))) + }) } fn lowercase_fn<'a>( @@ -226,14 +254,16 @@ fn lowercase_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let s = match &args[0] { - Some(resolved_pattern) => resolved_pattern.text(&state.files)?, - None => return Err(anyhow!("lowercase takes 1 argument")), - }; - Ok(ResolvedPattern::from_string(s.to_lowercase())) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let s = match &args[0] { + Some(resolved_pattern) => resolved_pattern.text(&state.files)?, + None => return Err(anyhow!("lowercase takes 1 argument")), + }; + Ok(ResolvedPattern::from_string(s.to_lowercase())) + }) } fn uppercase_fn<'a>( @@ -241,14 +271,16 @@ fn uppercase_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let s = match &args[0] { - Some(resolved_pattern) => resolved_pattern.text(&state.files)?, - None => return Err(anyhow!("uppercase takes 1 argument")), - }; - Ok(ResolvedPattern::from_string(s.to_uppercase())) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let s = match &args[0] { + Some(resolved_pattern) => resolved_pattern.text(&state.files)?, + None => return Err(anyhow!("uppercase takes 1 argument")), + }; + Ok(ResolvedPattern::from_string(s.to_uppercase())) + }) } fn text_fn<'a>( @@ -256,14 +288,16 @@ fn text_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let s = match args.first() { - Some(Some(resolved_pattern)) => resolved_pattern.text(&state.files)?, - _ => return Err(anyhow!("text takes 1 argument")), - }; - Ok(ResolvedPattern::from_string(s.to_string())) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let s = match args.first() { + Some(Some(resolved_pattern)) => resolved_pattern.text(&state.files)?, + _ => return Err(anyhow!("text takes 1 argument")), + }; + Ok(ResolvedPattern::from_string(s.to_string())) + }) } fn trim_fn<'a>( @@ -271,23 +305,25 @@ fn trim_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let trim_chars = match &args[1] { - Some(resolved_pattern) => resolved_pattern.text(&state.files)?, - None => return Err(anyhow!("trim takes 2 arguments: string and trim_chars")), - }; - - let s = match &args[0] { - Some(resolved_pattern) => resolved_pattern.text(&state.files)?, - None => return Err(anyhow!("trim takes 2 arguments: string and trim_chars")), - }; - - let trim_chars = trim_chars.chars().collect::>(); - let trim_chars = trim_chars.as_slice(); - let s = s.trim_matches(trim_chars).to_string(); - Ok(ResolvedPattern::from_string(s)) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let trim_chars = match &args[1] { + Some(resolved_pattern) => resolved_pattern.text(&state.files)?, + None => return Err(anyhow!("trim takes 2 arguments: string and trim_chars")), + }; + + let s = match &args[0] { + Some(resolved_pattern) => resolved_pattern.text(&state.files)?, + None => return Err(anyhow!("trim takes 2 arguments: string and trim_chars")), + }; + + let trim_chars = trim_chars.chars().collect::>(); + let trim_chars = trim_chars.as_slice(); + let s = s.trim_matches(trim_chars).to_string(); + Ok(ResolvedPattern::from_string(s)) + }) } fn split_fn<'a>( @@ -295,24 +331,28 @@ fn split_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let string = if let Some(string) = &args[0] { - string.text(&state.files)? - } else { - bail!("split requires parameter string") - }; - let separator = if let Some(separator) = &args[1] { - separator.text(&state.files)? - } else { - bail!("split requires parameter separator") - }; - let parts: Vector = string - .split(&separator.as_ref()) - .map(|s| ResolvedPattern::Snippets(vector![ResolvedSnippet::Text(s.to_string().into())])) - .collect(); - Ok(ResolvedPattern::List(parts)) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let string = if let Some(string) = &args[0] { + string.text(&state.files)? + } else { + bail!("split requires parameter string") + }; + let separator = if let Some(separator) = &args[1] { + separator.text(&state.files)? + } else { + bail!("split requires parameter separator") + }; + let parts: Vector = string + .split(&separator.as_ref()) + .map(|s| { + ResolvedPattern::Snippets(vector![ResolvedSnippet::Text(s.to_string().into())]) + }) + .collect(); + Ok(ResolvedPattern::List(parts)) + }) } fn random_fn<'a>( @@ -320,31 +360,37 @@ fn random_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - match args.as_slice() { - [Some(start), Some(end)] => { - let start = start.text(&state.files)?; - let end = end.text(&state.files)?; - let start = start.parse::().unwrap(); - let end = end.parse::().unwrap(); - // Inclusive range - let value = state.get_rng().gen_range(start..=end); - Ok(ResolvedPattern::Constant(Constant::Integer(value))) - } - [Some(_), None] => { - bail!("If you provide a start argument to random(), you must provide an end argument") - } - [None, Some(_)] => { - bail!("If you provide an end argument to random(), you must provide a start argument") - } - [None, None] => { - let value = state.get_rng().gen::(); - Ok(ResolvedPattern::Constant(Constant::Float(value))) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + match args.as_slice() { + [Some(start), Some(end)] => { + let start = start.text(&state.files)?; + let end = end.text(&state.files)?; + let start = start.parse::().unwrap(); + let end = end.parse::().unwrap(); + // Inclusive range + let value = state.get_rng().gen_range(start..=end); + Ok(ResolvedPattern::Constant(Constant::Integer(value))) + } + [Some(_), None] => { + bail!( + "If you provide a start argument to random(), you must provide an end argument" + ) + } + [None, Some(_)] => { + bail!( + "If you provide an end argument to random(), you must provide a start argument" + ) + } + [None, None] => { + let value = state.get_rng().gen::(); + Ok(ResolvedPattern::Constant(Constant::Float(value))) + } + _ => bail!("random() takes 0 or 2 arguments"), } - _ => bail!("random() takes 0 or 2 arguments"), - } + }) } fn join_fn<'a>( @@ -352,28 +398,30 @@ fn join_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let separator = &args[1]; - let separator = match separator { - Some(resolved_pattern) => resolved_pattern.text(&state.files)?, - None => return Err(anyhow!("trim takes 2 arguments: list and separator")), - }; - - let list = &args[0]; - let join = match list { - Some(ResolvedPattern::List(list)) => { - JoinFn::from_resolved(list.to_owned(), separator.to_string()) - } - Some(ResolvedPattern::Binding(binding)) => binding - .last() - .and_then(|b| JoinFn::from_list_binding(b, separator.to_string())) - .ok_or_else(|| anyhow!("join takes a list as the first argument"))?, - _ => bail!("join takes a list as the first argument"), - }; - let snippet = ResolvedSnippet::LazyFn(Box::new(LazyBuiltIn::Join(join))); - Ok(ResolvedPattern::from_resolved_snippet(snippet)) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let separator = &args[1]; + let separator = match separator { + Some(resolved_pattern) => resolved_pattern.text(&state.files)?, + None => return Err(anyhow!("trim takes 2 arguments: list and separator")), + }; + + let list = &args[0]; + let join = match list { + Some(ResolvedPattern::List(list)) => { + JoinFn::from_resolved(list.to_owned(), separator.to_string()) + } + Some(ResolvedPattern::Binding(binding)) => binding + .last() + .and_then(|b| JoinFn::from_list_binding(b, separator.to_string())) + .ok_or_else(|| anyhow!("join takes a list as the first argument"))?, + _ => bail!("join takes a list as the first argument"), + }; + let snippet = ResolvedSnippet::LazyFn(Box::new(LazyBuiltIn::Join(join))); + Ok(ResolvedPattern::from_resolved_snippet(snippet)) + }) } fn distinct_fn<'a>( @@ -381,39 +429,41 @@ fn distinct_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let list = args.into_iter().next().unwrap(); - match list { - Some(ResolvedPattern::List(list)) => { - let mut unique_list = Vector::new(); - for item in list { - if !unique_list.contains(&item) { - unique_list.push_back(item); +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let list = args.into_iter().next().unwrap(); + match list { + Some(ResolvedPattern::List(list)) => { + let mut unique_list = Vector::new(); + for item in list { + if !unique_list.contains(&item) { + unique_list.push_back(item); + } } + Ok(ResolvedPattern::List(unique_list)) } - Ok(ResolvedPattern::List(unique_list)) - } - Some(ResolvedPattern::Binding(binding)) => match binding.last() { - Some(b) => { - if let Some(list_items) = b.list_items() { - let mut unique_list = Vector::new(); - for item in list_items { - let resolved = ResolvedPattern::from_node(item); - if !unique_list.contains(&resolved) { - unique_list.push_back(resolved); + Some(ResolvedPattern::Binding(binding)) => match binding.last() { + Some(b) => { + if let Some(list_items) = b.list_items() { + let mut unique_list = Vector::new(); + for item in list_items { + let resolved = ResolvedPattern::from_node(item); + if !unique_list.contains(&resolved) { + unique_list.push_back(resolved); + } } + Ok(ResolvedPattern::List(unique_list)) + } else { + bail!("distinct takes a list as the first argument") } - Ok(ResolvedPattern::List(unique_list)) - } else { - bail!("distinct takes a list as the first argument") } - } - None => Ok(ResolvedPattern::Binding(binding)), - }, - _ => Err(anyhow!("distinct takes a list as the first argument")), - } + None => Ok(ResolvedPattern::Binding(binding)), + }, + _ => Err(anyhow!("distinct takes a list as the first argument")), + } + }) } // Shuffle a list @@ -422,45 +472,47 @@ fn shuffle_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let list = args - .into_iter() - .next() - .ok_or(anyhow!("shuffle requires one argument"))? - .ok_or(anyhow!( - "shuffle requires a non-null list as the first argument" - ))?; - match list { - ResolvedPattern::List(list) => { - let mut shuffled_list = list.iter().cloned().collect::>(); - shuffled_list.shuffle(state.get_rng()); - - Ok(ResolvedPattern::List(shuffled_list.into())) - } - ResolvedPattern::Binding(binding) => match binding.last() { - Some(b) => { - if let Some(list_items) = b.list_items() { - let mut list: Vec<_> = list_items.collect(); - list.shuffle(state.get_rng()); - let list: Vector<_> = - list.into_iter().map(ResolvedPattern::from_node).collect(); - Ok(ResolvedPattern::List(list)) - } else { - Err(anyhow!("shuffle takes a list as the first argument")) +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let list = args + .into_iter() + .next() + .ok_or(anyhow!("shuffle requires one argument"))? + .ok_or(anyhow!( + "shuffle requires a non-null list as the first argument" + ))?; + match list { + ResolvedPattern::List(list) => { + let mut shuffled_list = list.iter().cloned().collect::>(); + shuffled_list.shuffle(state.get_rng()); + + Ok(ResolvedPattern::List(shuffled_list.into())) + } + ResolvedPattern::Binding(binding) => match binding.last() { + Some(b) => { + if let Some(list_items) = b.list_items() { + let mut list: Vec<_> = list_items.collect(); + list.shuffle(state.get_rng()); + let list: Vector<_> = + list.into_iter().map(ResolvedPattern::from_node).collect(); + Ok(ResolvedPattern::List(list)) + } else { + Err(anyhow!("shuffle takes a list as the first argument")) + } } + None => Err(anyhow!("shuffle argument must be bound")), + }, + ResolvedPattern::Snippets(_) + | ResolvedPattern::Map(_) + | ResolvedPattern::File(_) + | ResolvedPattern::Files(_) + | ResolvedPattern::Constant(_) => { + Err(anyhow!("shuffle takes a list as the first argument")) } - None => Err(anyhow!("shuffle argument must be bound")), - }, - ResolvedPattern::Snippets(_) - | ResolvedPattern::Map(_) - | ResolvedPattern::File(_) - | ResolvedPattern::Files(_) - | ResolvedPattern::Constant(_) => { - Err(anyhow!("shuffle takes a list as the first argument")) } - } + }) } fn length_fn<'a>( @@ -468,34 +520,36 @@ fn length_fn<'a>( context: &'a MarzanoContext<'a>, state: &mut State<'a>, logs: &mut AnalysisLogs, -) -> Result> { - let args = patterns_to_resolved(args, state, context, logs)?; - - let list = args.into_iter().next().unwrap(); - match &list { - Some(ResolvedPattern::List(list)) => { - let length = list.len(); - Ok(ResolvedPattern::Constant(Constant::Integer(length as i64))) - } - Some(ResolvedPattern::Binding(binding)) => match binding.last() { +) -> Pin>>)>> { + Box::pin(async { + let args = patterns_to_resolved(args, state, context, logs).await?; + + let list = args.into_iter().next().unwrap(); + match &list { + Some(ResolvedPattern::List(list)) => { + let length = list.len(); + Ok(ResolvedPattern::Constant(Constant::Integer(length as i64))) + } + Some(ResolvedPattern::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().len() + }; + Ok(ResolvedPattern::Constant(Constant::Integer(length as i64))) + } + None => Err(anyhow!("length argument must be a list or string")), + }, Some(resolved_pattern) => { - let length = if let Some(list_items) = resolved_pattern.list_items() { - list_items.count() + if let Ok(text) = resolved_pattern.text(&state.files) { + let length = text.len(); + Ok(ResolvedPattern::Constant(Constant::Integer(length as i64))) } else { - resolved_pattern.text().len() - }; - Ok(ResolvedPattern::Constant(Constant::Integer(length as i64))) + Err(anyhow!("length argument must be a list or string")) + } } None => Err(anyhow!("length argument must be a list or string")), - }, - Some(resolved_pattern) => { - if let Ok(text) = resolved_pattern.text(&state.files) { - let length = text.len(); - Ok(ResolvedPattern::Constant(Constant::Integer(length as i64))) - } else { - Err(anyhow!("length argument must be a list or string")) - } } - None => Err(anyhow!("length argument must be a list or string")), - } + }) } diff --git a/crates/core/src/pattern/call.rs b/crates/core/src/pattern/call.rs index d0e988fe3..eb5e5c3a4 100644 --- a/crates/core/src/pattern/call.rs +++ b/crates/core/src/pattern/call.rs @@ -276,7 +276,7 @@ impl Name for Call { // todo parameters, and name should both be usize references // argument should throw an error if its not a parameter at compile time impl Matcher for Call { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -285,7 +285,9 @@ impl Matcher for Call { ) -> Result { let pattern_definition = &context.pattern_definitions()[self.index]; - pattern_definition.call(state, binding, context, logs, &self.args) + pattern_definition + .call(state, binding, context, logs, &self.args) + .await } } @@ -363,7 +365,7 @@ impl Name for PrCall { } impl Evaluator for PrCall { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -371,7 +373,9 @@ impl Evaluator for PrCall { ) -> Result { let predicate_definition = &context.predicate_definitions().get(self.index); if let Some(predicate_definition) = predicate_definition { - let predicator = predicate_definition.call(state, context, &self.args, logs)?; + let predicator = predicate_definition + .call(state, context, &self.args, logs) + .await?; Ok(FuncEvaluation { predicator, ret_val: None, @@ -379,7 +383,8 @@ impl Evaluator for PrCall { } else { let function_definition = &context.function_definitions().get(self.index); if let Some(function_definition) = function_definition { - let res = function_definition.call(state, context, &self.args, logs)?; + let res = + Box::pin(function_definition.call(state, context, &self.args, logs)).await?; Ok(res) } else { bail!( diff --git a/crates/core/src/pattern/code_snippet.rs b/crates/core/src/pattern/code_snippet.rs index d716d417e..a5416b847 100644 --- a/crates/core/src/pattern/code_snippet.rs +++ b/crates/core/src/pattern/code_snippet.rs @@ -97,7 +97,7 @@ impl Name for CodeSnippet { impl Matcher for CodeSnippet { // wrong, but whatever for now - fn execute<'a>( + async fn execute<'a>( &'a self, resolved_pattern: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -125,7 +125,9 @@ impl Matcher for CodeSnippet { .iter() .find(|(id, _)| *id == node.node.kind_id()) { - pattern.execute(resolved_pattern, state, context, logs) + pattern + .execute(resolved_pattern, state, context, logs) + .await } else { Ok(false) } diff --git a/crates/core/src/pattern/contains.rs b/crates/core/src/pattern/contains.rs index 972e7b915..933f2076a 100644 --- a/crates/core/src/pattern/contains.rs +++ b/crates/core/src/pattern/contains.rs @@ -70,7 +70,7 @@ impl Name for Contains { } } -fn execute_until<'a>( +async fn execute_until<'a>( init_state: &mut State<'a>, node: &Node<'a>, src: &'a str, @@ -88,7 +88,10 @@ fn execute_until<'a>( let node_lhs = ResolvedPattern::from_node(NodeWithSource::new(node, src)); let state = cur_state.clone(); - if the_contained.execute(&node_lhs, &mut cur_state, context, logs)? { + if the_contained + .execute(&node_lhs, &mut cur_state, context, logs) + .await? + { did_match = true; } else { cur_state = state; @@ -96,7 +99,7 @@ fn execute_until<'a>( let mut state = cur_state.clone(); let skip_children = if let Some(until) = until { - until.execute(&node_lhs, &mut state, context, logs)? + until.execute(&node_lhs, &mut state, context, logs).await? } else { false }; @@ -126,7 +129,7 @@ fn execute_until<'a>( // Contains and within should call the same function taking an iterator as an argument // even better two arguments an accumulator and an iterator. impl Matcher for Contains { - fn execute<'a>( + async fn execute<'a>( &'a self, resolved_pattern: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -146,17 +149,21 @@ impl Matcher for Contains { &self.contains, &self.until, ) + .await } else if let Some(list_items) = binding.list_items() { let mut did_match = false; let mut cur_state = init_state.clone(); for item in list_items { let state = cur_state.clone(); - if self.execute( - &ResolvedPattern::from_node(item), - &mut cur_state, - context, - logs, - )? { + if self + .execute( + &ResolvedPattern::from_node(item), + &mut cur_state, + context, + logs, + ) + .await? + { did_match = true; } else { cur_state = state; @@ -171,6 +178,7 @@ impl Matcher for Contains { // this seems like an infinite loop, todo return false? self.contains .execute(resolved_pattern, init_state, context, logs) + .await } else { Ok(false) } @@ -180,7 +188,7 @@ impl Matcher for Contains { let mut did_match = false; for element in elements { let state = cur_state.clone(); - if self.execute(element, &mut cur_state, context, logs)? { + if self.execute(element, &mut cur_state, context, logs).await? { did_match = true; } else { cur_state = state; @@ -198,30 +206,33 @@ impl Matcher for Contains { let prev_state = cur_state.clone(); if self .contains - .execute(resolved_pattern, &mut cur_state, context, logs)? + .execute(resolved_pattern, &mut cur_state, context, logs) + .await? { did_match = true; } else { cur_state = prev_state; } let prev_state = cur_state.clone(); - if self.contains.execute( - &file.name(&cur_state.files), - &mut cur_state, - context, - logs, - )? { + if self + .contains + .execute(&file.name(&cur_state.files), &mut cur_state, context, logs) + .await? + { did_match = true; } else { cur_state = prev_state; } let prev_state = cur_state.clone(); - if self.execute( - &file.binding(&cur_state.files), - &mut cur_state, - context, - logs, - )? { + if self + .execute( + &file.binding(&cur_state.files), + &mut cur_state, + context, + logs, + ) + .await? + { did_match = true; } else { cur_state = prev_state; @@ -238,14 +249,15 @@ impl Matcher for Contains { let prev_state = cur_state.clone(); if self .contains - .execute(resolved_pattern, &mut cur_state, context, logs)? + .execute(resolved_pattern, &mut cur_state, context, logs) + .await? { did_match = true; } else { cur_state = prev_state; } let prev_state = cur_state.clone(); - if self.execute(files, &mut cur_state, context, logs)? { + if self.execute(files, &mut cur_state, context, logs).await? { did_match = true; } else { cur_state = prev_state; @@ -272,7 +284,10 @@ impl Matcher for Contains { LazyBuiltIn::Join(j) => ResolvedPattern::List(j.list.clone()), }, }; - if self.execute(&resolved, &mut cur_state, context, logs)? { + if self + .execute(&resolved, &mut cur_state, context, logs) + .await? + { did_match = true; } else { cur_state = state; diff --git a/crates/core/src/pattern/divide.rs b/crates/core/src/pattern/divide.rs index 994dce43c..502a8a718 100644 --- a/crates/core/src/pattern/divide.rs +++ b/crates/core/src/pattern/divide.rs @@ -63,24 +63,24 @@ impl Divide { Ok(Self::new(left, right)) } - pub(crate) fn call<'a>( + pub(crate) async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let res = self.evaluate(state, context, logs)?; + let res = self.evaluate(state, context, logs).await?; Ok(ResolvedPattern::Constant(Constant::Float(res))) } - fn evaluate<'a>( + async fn evaluate<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let lhs = self.lhs.float(state, context, logs)?; - let rhs = self.rhs.float(state, context, logs)?; + let lhs = self.lhs.float(state, context, logs).await?; + let rhs = self.rhs.float(state, context, logs).await?; let res = lhs / rhs; Ok(res) } @@ -93,7 +93,7 @@ impl Name for Divide { } impl Matcher for Divide { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -102,7 +102,7 @@ impl Matcher for Divide { ) -> Result { let binding_text = binding.text(&state.files)?; let binding_int = binding_text.parse::()?; - let target = self.evaluate(state, context, logs)?; + let target = self.evaluate(state, context, logs).await?; Ok(binding_int == target) } } diff --git a/crates/core/src/pattern/dynamic_snippet.rs b/crates/core/src/pattern/dynamic_snippet.rs index 3b74bada9..073bec823 100644 --- a/crates/core/src/pattern/dynamic_snippet.rs +++ b/crates/core/src/pattern/dynamic_snippet.rs @@ -49,13 +49,13 @@ pub enum DynamicPattern { } impl DynamicPattern { - pub fn text<'a>( + pub async fn text<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let resolved = ResolvedPattern::from_dynamic_pattern(self, state, context, logs)?; + let resolved = ResolvedPattern::from_dynamic_pattern(self, state, context, logs).await?; Ok(resolved.text(&state.files)?.to_string()) } } @@ -67,14 +67,14 @@ impl Name for DynamicPattern { } impl Matcher for DynamicPattern { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - if binding.text(&state.files)? == self.text(state, context, logs)? { + if binding.text(&state.files)? == self.text(state, context, logs).await? { Ok(true) } else { Ok(false) diff --git a/crates/core/src/pattern/equal.rs b/crates/core/src/pattern/equal.rs index f2fa3cf65..7f65619e4 100644 --- a/crates/core/src/pattern/equal.rs +++ b/crates/core/src/pattern/equal.rs @@ -73,14 +73,14 @@ impl Name for Equal { } impl Evaluator for Equal { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { let lhs_text = self.var.text(state)?; - let rhs_text = self.pattern.text(state, context, logs)?; + let rhs_text = self.pattern.text(state, context, logs).await?; Ok(FuncEvaluation { predicator: lhs_text == rhs_text, ret_val: None, diff --git a/crates/core/src/pattern/every.rs b/crates/core/src/pattern/every.rs index 7e51ddc80..b00775b21 100644 --- a/crates/core/src/pattern/every.rs +++ b/crates/core/src/pattern/every.rs @@ -55,7 +55,7 @@ impl Name for Every { } impl Matcher for Every { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -72,12 +72,11 @@ impl Matcher for Every { }; for item in list_items { - if !self.pattern.execute( - &ResolvedPattern::from_node(item), - init_state, - context, - logs, - )? { + if !self + .pattern + .execute(&ResolvedPattern::from_node(item), init_state, context, logs) + .await? + { return Ok(false); } } @@ -86,7 +85,7 @@ impl Matcher for Every { ResolvedPattern::List(elements) => { let pattern = &self.pattern; for element in elements { - if !pattern.execute(element, init_state, context, logs)? { + if !pattern.execute(element, init_state, context, logs).await? { return Ok(false); } } @@ -98,7 +97,10 @@ impl Matcher for Every { let key = ResolvedPattern::Constant(crate::binding::Constant::String(key.clone())); let resolved = ResolvedPattern::List(vector![key, value.clone()]); - if !pattern.execute(&resolved, init_state, context, logs)? { + if !pattern + .execute(&resolved, init_state, context, logs) + .await? + { return Ok(false); } } diff --git a/crates/core/src/pattern/file_pattern.rs b/crates/core/src/pattern/file_pattern.rs index ace0c3b25..6d6a0d919 100644 --- a/crates/core/src/pattern/file_pattern.rs +++ b/crates/core/src/pattern/file_pattern.rs @@ -20,7 +20,7 @@ impl FilePattern { } impl Matcher for FilePattern { - fn execute<'a>( + async fn execute<'a>( &'a self, resolved_pattern: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -31,13 +31,15 @@ impl Matcher for FilePattern { ResolvedPattern::File(file) => { if !self .name - .execute(&file.name(&state.files), state, context, logs)? + .execute(&file.name(&state.files), state, context, logs) + .await? { return Ok(false); } if !self .body - .execute(&file.binding(&state.files), state, context, logs)? + .execute(&file.binding(&state.files), state, context, logs) + .await? { return Ok(false); } diff --git a/crates/core/src/pattern/files.rs b/crates/core/src/pattern/files.rs index 5e61543ec..189d597c3 100644 --- a/crates/core/src/pattern/files.rs +++ b/crates/core/src/pattern/files.rs @@ -20,7 +20,7 @@ impl Files { } impl Matcher for Files { - fn execute<'a>( + async fn execute<'a>( &'a self, resolved_pattern: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -28,10 +28,12 @@ impl Matcher for Files { logs: &mut AnalysisLogs, ) -> Result { match resolved_pattern { - ResolvedPattern::Files(files) => self.pattern.execute(files, state, context, logs), + ResolvedPattern::Files(files) => { + self.pattern.execute(files, state, context, logs).await + } ResolvedPattern::File(_) => { let files = ResolvedPattern::List(vector![resolved_pattern.to_owned()]); - self.pattern.execute(&files, state, context, logs) + self.pattern.execute(&files, state, context, logs).await } ResolvedPattern::Binding(_) | ResolvedPattern::Snippets(_) diff --git a/crates/core/src/pattern/float_constant.rs b/crates/core/src/pattern/float_constant.rs index ea363d7a8..84b388924 100644 --- a/crates/core/src/pattern/float_constant.rs +++ b/crates/core/src/pattern/float_constant.rs @@ -32,7 +32,7 @@ impl Name for FloatConstant { } impl Matcher for FloatConstant { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, diff --git a/crates/core/src/pattern/function_definition.rs b/crates/core/src/pattern/function_definition.rs index e243b4d06..2cb15de54 100644 --- a/crates/core/src/pattern/function_definition.rs +++ b/crates/core/src/pattern/function_definition.rs @@ -19,7 +19,7 @@ use super::{ }; pub(crate) trait FunctionDefinition { - fn call<'a>( + async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -109,7 +109,7 @@ impl GritFunctionDefinition { } impl FunctionDefinition for GritFunctionDefinition { - fn call<'a>( + async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -117,7 +117,7 @@ impl FunctionDefinition for GritFunctionDefinition { logs: &mut AnalysisLogs, ) -> Result { state.reset_vars(self.scope, args); - self.function.execute_func(state, context, logs) + self.function.execute_func(state, context, logs).await } } @@ -199,7 +199,7 @@ impl ForeignFunctionDefinition { impl FunctionDefinition for ForeignFunctionDefinition { #[cfg(not(feature = "external_functions_common"))] - fn call<'a>( + async fn call<'a>( &'a self, _state: &mut State<'a>, _context: &'a impl Context, @@ -209,7 +209,7 @@ impl FunctionDefinition for ForeignFunctionDefinition { bail!("External functions are not enabled in your environment") } #[cfg(feature = "external_functions_common")] - fn call<'a>( + async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -222,7 +222,7 @@ impl FunctionDefinition for ForeignFunctionDefinition { .map(|(name, _)| name.clone()) .collect::>(); - let resolved = patterns_to_resolved(args, state, context, logs)?; + let resolved = patterns_to_resolved(args, state, context, logs).await?; let mut cow_resolved = Vec::with_capacity(resolved.len()); for r in resolved.iter() { diff --git a/crates/core/src/pattern/functions.rs b/crates/core/src/pattern/functions.rs index 59f959bd7..5a7b9ee3d 100644 --- a/crates/core/src/pattern/functions.rs +++ b/crates/core/src/pattern/functions.rs @@ -16,7 +16,7 @@ pub(crate) struct FuncEvaluation<'a> { } pub(crate) trait Evaluator: Debug { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -31,7 +31,7 @@ pub struct CallFunction { } pub(crate) trait GritCall { - fn call<'a>( + async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -46,7 +46,7 @@ impl CallFunction { } impl GritCall for CallFunction { - fn call<'a>( + async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -55,7 +55,8 @@ impl GritCall for CallFunction { let function_definition = &context.function_definitions()[self.index]; match function_definition - .call(state, context, &self.args, logs)? + .call(state, context, &self.args, logs) + .await? .ret_val { Some(pattern) => Ok(pattern), @@ -83,7 +84,7 @@ impl CallForeignFunction { } impl GritCall for CallForeignFunction { - fn call<'a>( + async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -92,7 +93,8 @@ impl GritCall for CallForeignFunction { let function_definition = &context.foreign_function_definitions()[self.index]; match function_definition - .call(state, context, &self.args, logs)? + .call(state, context, &self.args, logs) + .await? .ret_val { Some(pattern) => Ok(pattern), diff --git a/crates/core/src/pattern/if.rs b/crates/core/src/pattern/if.rs index 72540b45b..1731af945 100644 --- a/crates/core/src/pattern/if.rs +++ b/crates/core/src/pattern/if.rs @@ -89,7 +89,7 @@ impl Name for If { } impl Matcher for If { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -97,11 +97,16 @@ impl Matcher for If { logs: &mut AnalysisLogs, ) -> Result { let mut state = init_state.clone(); - if self.if_.execute_func(&mut state, context, logs)?.predicator { + if self + .if_ + .execute_func(&mut state, context, logs) + .await? + .predicator + { *init_state = state; - self.then.execute(binding, init_state, context, logs) + self.then.execute(binding, init_state, context, logs).await } else { - self.else_.execute(binding, init_state, context, logs) + self.else_.execute(binding, init_state, context, logs).await } } } @@ -179,22 +184,22 @@ impl Name for PrIf { } impl Evaluator for PrIf { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, init_state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { let mut state = init_state.clone(); - let condition = self.if_.execute_func(&mut state, context, logs)?; + let condition = self.if_.execute_func(&mut state, context, logs).await?; if condition.ret_val.is_some() { bail!("Cannot return from within if condition"); } if condition.predicator { *init_state = state; - self.then.execute_func(init_state, context, logs) + self.then.execute_func(init_state, context, logs).await } else { - self.else_.execute_func(init_state, context, logs) + self.else_.execute_func(init_state, context, logs).await } } } diff --git a/crates/core/src/pattern/includes.rs b/crates/core/src/pattern/includes.rs index ea841d69a..647da9c11 100644 --- a/crates/core/src/pattern/includes.rs +++ b/crates/core/src/pattern/includes.rs @@ -56,7 +56,7 @@ impl Name for Includes { // Includes and within should call the same function taking an iterator as an argument // even better two arguments an accumulator and an iterator. impl Matcher for Includes { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -65,7 +65,9 @@ impl Matcher for Includes { ) -> Result { match &self.includes { Pattern::Regex(pattern) => { - pattern.execute_matching(binding, state, context, logs, false) + pattern + .execute_matching(binding, state, context, logs, false) + .await } Pattern::ASTNode(_) | Pattern::List(_) @@ -119,7 +121,8 @@ impl Matcher for Includes { | Pattern::Dots | Pattern::Sequential(_) | Pattern::Like(_) => { - let resolved = ResolvedPattern::from_pattern(&self.includes, state, context, logs)?; + let resolved = + ResolvedPattern::from_pattern(&self.includes, state, context, logs).await?; let substring = resolved.text(&state.files)?; let string = binding.text(&state.files)?; if string.contains(&*substring) { diff --git a/crates/core/src/pattern/int_constant.rs b/crates/core/src/pattern/int_constant.rs index 177510266..353cc3a95 100644 --- a/crates/core/src/pattern/int_constant.rs +++ b/crates/core/src/pattern/int_constant.rs @@ -32,7 +32,7 @@ impl Name for IntConstant { } impl Matcher for IntConstant { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, diff --git a/crates/core/src/pattern/like.rs b/crates/core/src/pattern/like.rs index 2516dd0c7..a7a458614 100644 --- a/crates/core/src/pattern/like.rs +++ b/crates/core/src/pattern/like.rs @@ -74,7 +74,7 @@ impl Name for Like { impl Matcher for Like { #[cfg(feature = "embeddings")] - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -92,7 +92,7 @@ impl Matcher for Like { } #[cfg(not(feature = "embeddings"))] - fn execute<'a>( + async fn execute<'a>( &'a self, _binding: &ResolvedPattern<'a>, _state: &mut State<'a>, diff --git a/crates/core/src/pattern/limit.rs b/crates/core/src/pattern/limit.rs index b9344225b..b2ce5b834 100644 --- a/crates/core/src/pattern/limit.rs +++ b/crates/core/src/pattern/limit.rs @@ -71,7 +71,7 @@ impl Name for Limit { } impl Matcher for Limit { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -79,13 +79,13 @@ impl Matcher for Limit { logs: &mut AnalysisLogs, ) -> Result { if context.ignore_limit_pattern() { - let res = self.pattern.execute(binding, state, context, logs)?; + let res = self.pattern.execute(binding, state, context, logs).await?; return Ok(res); } if self.invocation_count.load(Ordering::Relaxed) >= self.limit { return Ok(false); } - let res = self.pattern.execute(binding, state, context, logs)?; + let res = self.pattern.execute(binding, state, context, logs).await?; if !res { return Ok(false); } diff --git a/crates/core/src/pattern/list.rs b/crates/core/src/pattern/list.rs index a64adbc26..328a9fa36 100644 --- a/crates/core/src/pattern/list.rs +++ b/crates/core/src/pattern/list.rs @@ -112,7 +112,7 @@ impl Name for List { } impl Matcher for List { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut super::state::State<'a>, @@ -130,12 +130,12 @@ impl Matcher for List { .map(Cow::Owned) .collect(); - execute_assoc(&self.patterns, &children, state, context, logs) + execute_assoc(&self.patterns, &children, state, context, logs).await } ResolvedPattern::List(patterns) => { let patterns: Vec>> = patterns.into_iter().map(Cow::Borrowed).collect(); - execute_assoc(&self.patterns, &patterns, state, context, logs) + execute_assoc(&self.patterns, &patterns, state, context, logs).await } ResolvedPattern::Snippets(_) | ResolvedPattern::File(_) @@ -146,9 +146,9 @@ impl Matcher for List { } } -fn execute_assoc<'a>( +async fn execute_assoc<'a>( patterns: &'a [Pattern], - children: &[Cow>], + children: &[Cow<'_, ResolvedPattern<'a>>], current_state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, @@ -161,7 +161,10 @@ fn execute_assoc<'a>( return Ok(false); } let first_node = children[0].clone(); - if pattern_for_first_node.execute(&first_node, &mut working_state, context, logs)? { + if pattern_for_first_node + .execute(&first_node, &mut working_state, context, logs) + .await? + { *current_state = working_state; Ok(true) } else { @@ -171,7 +174,10 @@ fn execute_assoc<'a>( // short circuit for common case [Pattern::Dots, pattern_for_last_node] => { if let Some(last_node) = children.last() { - if pattern_for_last_node.execute(last_node, &mut working_state, context, logs)? { + if pattern_for_last_node + .execute(last_node, &mut working_state, context, logs) + .await? + { *current_state = working_state; Ok(true) } else { @@ -186,14 +192,17 @@ fn execute_assoc<'a>( return Err(anyhow!("Multiple subsequent dots are not allowed.")); } for index in 0..children.len() { - if head_pattern.execute(&children[index], &mut working_state, context, logs)? + if head_pattern + .execute(&children[index], &mut working_state, context, logs) + .await? && execute_assoc( tail_patterns, &children[index + 1..], &mut working_state, context, logs, - )? + ) + .await? { *current_state = working_state; return Ok(true); @@ -204,7 +213,10 @@ fn execute_assoc<'a>( [Pattern::Dots] => Ok(true), [only_pattern] => { if children.len() == 1 { - if only_pattern.execute(&children[0], &mut working_state, context, logs)? { + if only_pattern + .execute(&children[0], &mut working_state, context, logs) + .await? + { *current_state = working_state; Ok(true) } else { @@ -216,9 +228,13 @@ fn execute_assoc<'a>( } [head_pattern, tail_patterns @ ..] => match children { [head_node, tail_nodes @ ..] => { - if head_pattern.execute(head_node, &mut working_state, context, logs)? { + if head_pattern + .execute(head_node, &mut working_state, context, logs) + .await? + { if let Ok(true) = execute_assoc(tail_patterns, tail_nodes, &mut working_state, context, logs) + .await { *current_state = working_state; Ok(true) diff --git a/crates/core/src/pattern/list_index.rs b/crates/core/src/pattern/list_index.rs index 634dc7d90..3b7b4ae22 100644 --- a/crates/core/src/pattern/list_index.rs +++ b/crates/core/src/pattern/list_index.rs @@ -219,7 +219,7 @@ impl Name for ListIndex { } impl Matcher for ListIndex { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -233,7 +233,7 @@ impl Matcher for ListIndex { Some(PatternOrResolved::ResolvedBinding(r)) => { execute_resolved_with_binding(&r, binding, state) } - Some(PatternOrResolved::Pattern(p)) => p.execute(binding, state, context, logs), + Some(PatternOrResolved::Pattern(p)) => p.execute(binding, state, context, logs).await, None => Ok( matches!(binding, ResolvedPattern::Constant(Constant::Boolean(false))) || binding.matches_undefined(), diff --git a/crates/core/src/pattern/log.rs b/crates/core/src/pattern/log.rs index f4166b504..bbeb7a42c 100644 --- a/crates/core/src/pattern/log.rs +++ b/crates/core/src/pattern/log.rs @@ -29,7 +29,7 @@ impl Log { Self { variable, message } } - fn add_log<'a>( + async fn add_log<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -37,7 +37,8 @@ impl Log { ) -> Result { let mut message = String::new(); if let Some(user_message) = &self.message { - let resolved = ResolvedPattern::from_pattern(user_message, state, context, logs)?; + let resolved = + ResolvedPattern::from_pattern(user_message, state, context, logs).await?; let text = resolved.text(&state.files)?; message.push_str(&format!("{}\n", text)); } @@ -122,25 +123,25 @@ impl Log { } impl Matcher for Log { - fn execute<'a>( + async fn execute<'a>( &'a self, _binding: &super::resolved_pattern::ResolvedPattern<'a>, state: &mut super::state::State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - self.add_log(state, context, logs) + self.add_log(state, context, logs).await } } impl Evaluator for Log { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let predicator = self.add_log(state, context, logs)?; + let predicator = self.add_log(state, context, logs).await?; Ok(FuncEvaluation { predicator, ret_val: None, diff --git a/crates/core/src/pattern/map.rs b/crates/core/src/pattern/map.rs index 7e8fe8924..4a4bc832d 100644 --- a/crates/core/src/pattern/map.rs +++ b/crates/core/src/pattern/map.rs @@ -71,7 +71,7 @@ impl Name for GritMap { } impl Matcher for GritMap { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut super::state::State<'a>, @@ -81,7 +81,7 @@ impl Matcher for GritMap { if let ResolvedPattern::Map(map) = binding { for element in map.iter() { if let Some(pattern) = self.elements.get(element.0) { - if !pattern.execute(element.1, state, context, logs)? { + if !pattern.execute(element.1, state, context, logs).await? { return Ok(false); } } else { diff --git a/crates/core/src/pattern/match.rs b/crates/core/src/pattern/match.rs index f8c8f1394..27768e751 100644 --- a/crates/core/src/pattern/match.rs +++ b/crates/core/src/pattern/match.rs @@ -68,7 +68,7 @@ impl Name for Match { } impl Evaluator for Match { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -80,17 +80,24 @@ impl Evaluator for Match { let var_content = &state.bindings[var.scope].last().unwrap()[var.index]; let predicator = if let Some(pattern) = &self.pattern { if let Some(important_binding) = &var_content.value { - pattern.execute(&important_binding.clone(), state, context, logs)? + pattern + .execute(&important_binding.clone(), state, context, logs) + .await? } else if let Some(var_pattern) = var_content.pattern { let resolved_pattern = - ResolvedPattern::from_pattern(var_pattern, state, context, logs)?; - pattern.execute(&resolved_pattern, state, context, logs)? + ResolvedPattern::from_pattern(var_pattern, state, context, logs) + .await?; + pattern + .execute(&resolved_pattern, state, context, logs) + .await? } else if let Some(Pattern::BooleanConstant(b)) = &self.pattern { if !b.value { true } else { let resolved_pattern = ResolvedPattern::undefined(); - let res = pattern.execute(&resolved_pattern, state, context, logs)?; + let res = pattern + .execute(&resolved_pattern, state, context, logs) + .await?; if !res { let message = format!( "Attempted to match against undefined variable {}", @@ -102,7 +109,9 @@ impl Evaluator for Match { } } else { let resolved_pattern = ResolvedPattern::undefined(); - let res = pattern.execute(&resolved_pattern, state, context, logs)?; + let res = pattern + .execute(&resolved_pattern, state, context, logs) + .await?; if !res { let message = format!( "Attempted to match against undefined variable {}", @@ -126,9 +135,11 @@ impl Evaluator for Match { } Container::Accessor(accessor) => { let resolved_accessor = - ResolvedPattern::from_accessor(accessor, state, context, logs)?; + ResolvedPattern::from_accessor(accessor, state, context, logs).await?; let predicator = if let Some(pattern) = &self.pattern { - pattern.execute(&resolved_accessor, state, context, logs)? + pattern + .execute(&resolved_accessor, state, context, logs) + .await? } else { resolved_accessor.matches_undefined() }; @@ -139,9 +150,11 @@ impl Evaluator for Match { } Container::ListIndex(index) => { let resolved_accessor = - ResolvedPattern::from_list_index(index, state, context, logs)?; + ResolvedPattern::from_list_index(index, state, context, logs).await?; let predicator = if let Some(pattern) = &self.pattern { - pattern.execute(&resolved_accessor, state, context, logs)? + pattern + .execute(&resolved_accessor, state, context, logs) + .await? } else { resolved_accessor.matches_undefined() }; diff --git a/crates/core/src/pattern/maybe.rs b/crates/core/src/pattern/maybe.rs index 486b998bc..9143dca98 100644 --- a/crates/core/src/pattern/maybe.rs +++ b/crates/core/src/pattern/maybe.rs @@ -49,7 +49,7 @@ impl Maybe { } impl Matcher for Maybe { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -57,7 +57,11 @@ impl Matcher for Maybe { logs: &mut AnalysisLogs, ) -> Result { let mut state = init_state.clone(); - if self.pattern.execute(binding, &mut state, context, logs)? { + if self + .pattern + .execute(binding, &mut state, context, logs) + .await? + { *init_state = state; } Ok(true) @@ -105,7 +109,7 @@ impl PrMaybe { } impl Evaluator for PrMaybe { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, init_state: &mut State<'a>, context: &'a impl Context, @@ -114,7 +118,8 @@ impl Evaluator for PrMaybe { let mut state = init_state.clone(); if self .predicate - .execute_func(&mut state, context, logs)? + .execute_func(&mut state, context, logs) + .await? .predicator { *init_state = state; diff --git a/crates/core/src/pattern/modulo.rs b/crates/core/src/pattern/modulo.rs index 6f0a434e8..59df180d8 100644 --- a/crates/core/src/pattern/modulo.rs +++ b/crates/core/src/pattern/modulo.rs @@ -62,24 +62,24 @@ impl Modulo { Ok(Self::new(left, right)) } - pub(crate) fn call<'a>( + pub(crate) async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let res = self.evaluate(state, context, logs)?; + let res = self.evaluate(state, context, logs).await?; Ok(ResolvedPattern::Constant(Constant::Integer(res))) } - fn evaluate<'a>( + async fn evaluate<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let lhs = self.lhs.text(state, context, logs)?; - let rhs = self.rhs.text(state, context, logs)?; + let lhs = self.lhs.text(state, context, logs).await?; + let rhs = self.rhs.text(state, context, logs).await?; let lhs_int = lhs.parse::()?; let rhs_int = rhs.parse::()?; let res = lhs_int % rhs_int; @@ -94,7 +94,7 @@ impl Name for Modulo { } impl Matcher for Modulo { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -103,7 +103,7 @@ impl Matcher for Modulo { ) -> Result { let binding_text = binding.text(&state.files)?; let binding_int = binding_text.parse::()?; - let target = self.evaluate(state, context, logs)?; + let target = self.evaluate(state, context, logs).await?; Ok(binding_int == target) } } diff --git a/crates/core/src/pattern/multiply.rs b/crates/core/src/pattern/multiply.rs index a4f87143b..3825aa3ba 100644 --- a/crates/core/src/pattern/multiply.rs +++ b/crates/core/src/pattern/multiply.rs @@ -62,24 +62,24 @@ impl Multiply { Ok(Self::new(left, right)) } - pub(crate) fn call<'a>( + pub(crate) async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let res = self.evaluate(state, context, logs)?; + let res = self.evaluate(state, context, logs).await?; Ok(ResolvedPattern::Constant(Constant::Float(res))) } - fn evaluate<'a>( + async fn evaluate<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let lhs = self.lhs.float(state, context, logs)?; - let rhs = self.rhs.float(state, context, logs)?; + let lhs = self.lhs.float(state, context, logs).await?; + let rhs = self.rhs.float(state, context, logs).await?; let res = lhs * rhs; Ok(res) } @@ -92,7 +92,7 @@ impl Name for Multiply { } impl Matcher for Multiply { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -101,7 +101,7 @@ impl Matcher for Multiply { ) -> Result { let binding_text = binding.text(&state.files)?; let binding_int = binding_text.parse::()?; - let target = self.evaluate(state, context, logs)?; + let target = self.evaluate(state, context, logs).await?; Ok(binding_int == target) } } diff --git a/crates/core/src/pattern/not.rs b/crates/core/src/pattern/not.rs index c3a3b73de..05bb10ddc 100644 --- a/crates/core/src/pattern/not.rs +++ b/crates/core/src/pattern/not.rs @@ -76,7 +76,7 @@ impl Name for Not { } impl Matcher for Not { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -85,7 +85,8 @@ impl Matcher for Not { ) -> Result { Ok(!self .pattern - .execute(binding, &mut state.clone(), context, logs)?) + .execute(binding, &mut state.clone(), context, logs) + .await?) } } @@ -148,7 +149,7 @@ impl Name for PrNot { } impl Evaluator for PrNot { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -156,7 +157,8 @@ impl Evaluator for PrNot { ) -> Result { let res = self .predicate - .execute_func(&mut state.clone(), context, logs)?; + .execute_func(&mut state.clone(), context, logs) + .await?; if res.ret_val.is_some() { bail!("Cannot return from within not clause"); } diff --git a/crates/core/src/pattern/or.rs b/crates/core/src/pattern/or.rs index 637a608f1..966b7dee9 100644 --- a/crates/core/src/pattern/or.rs +++ b/crates/core/src/pattern/or.rs @@ -64,7 +64,7 @@ impl Name for Or { } impl Matcher for Or { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -82,7 +82,7 @@ impl Matcher for Or { } } let mut state = init_state.clone(); - let res = p.execute(binding, &mut state, context, logs)?; + let res = p.execute(binding, &mut state, context, logs).await?; if res { *init_state = state; return Ok(true); @@ -91,7 +91,7 @@ impl Matcher for Or { } else { for p in self.patterns.iter() { let mut state = init_state.clone(); - let res = p.execute(binding, &mut state, context, logs)?; + let res = p.execute(binding, &mut state, context, logs).await?; if res { *init_state = state; return Ok(true); @@ -152,7 +152,7 @@ impl Name for PrOr { } impl Evaluator for PrOr { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, init_state: &mut State<'a>, context: &'a impl Context, @@ -160,7 +160,7 @@ impl Evaluator for PrOr { ) -> Result { for p in self.predicates.iter() { let mut state = init_state.clone(); - let res = p.execute_func(&mut state, context, logs)?; + let res = p.execute_func(&mut state, context, logs).await?; if res.predicator || res.ret_val.is_some() { *init_state = state; return Ok(res); diff --git a/crates/core/src/pattern/pattern_definition.rs b/crates/core/src/pattern/pattern_definition.rs index c0afcfce0..cbc816629 100644 --- a/crates/core/src/pattern/pattern_definition.rs +++ b/crates/core/src/pattern/pattern_definition.rs @@ -95,7 +95,7 @@ impl PatternDefinition { Ok(()) } - pub(crate) fn call<'a>( + pub(crate) async fn call<'a>( &'a self, state: &mut State<'a>, binding: &ResolvedPattern<'a>, @@ -104,7 +104,7 @@ impl PatternDefinition { args: &'a [Option], ) -> Result { state.reset_vars(self.scope, args); - let res = self.pattern.execute(binding, state, context, logs); + let res = self.pattern.execute(binding, state, context, logs).await; let fn_state = state.bindings[self.scope].pop_back().unwrap(); let cur_fn_state = state.bindings[self.scope].back_mut().unwrap(); diff --git a/crates/core/src/pattern/patterns.rs b/crates/core/src/pattern/patterns.rs index 21688d44d..e00fea2cc 100644 --- a/crates/core/src/pattern/patterns.rs +++ b/crates/core/src/pattern/patterns.rs @@ -54,7 +54,7 @@ pub(crate) trait Matcher: Debug { // it is important that any implementors of Pattern // do not compute-expensive things in execute // it should be stored somewhere in the struct of the implementor - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -604,24 +604,27 @@ impl Pattern { } // todo this should return a cow, but currently can't figure out lifetimes - pub fn text<'a>( + pub async fn text<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - Ok(ResolvedPattern::from_pattern(self, state, context, logs)? + Ok(ResolvedPattern::from_pattern(self, state, context, logs) + .await? .text(&state.files)? .to_string()) } - pub(crate) fn float<'a>( + pub(crate) async fn float<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - ResolvedPattern::from_pattern(self, state, context, logs)?.float(&state.files) + ResolvedPattern::from_pattern(self, state, context, logs) + .await? + .float(&state.files) } // use a struct @@ -1069,7 +1072,7 @@ impl Name for Pattern { } impl Matcher for Pattern { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -1086,19 +1089,25 @@ impl Matcher for Pattern { } match self { - Pattern::ASTNode(ast_node) => ast_node.execute(binding, state, context, logs), - Pattern::Some(some) => some.execute(binding, state, context, logs), - Pattern::Every(every) => every.execute(binding, state, context, logs), - Pattern::List(patterns) => patterns.execute(binding, state, context, logs), - Pattern::ListIndex(index) => index.execute(binding, state, context, logs), - Pattern::Map(map) => map.execute(binding, state, context, logs), - Pattern::Accessor(accessor) => accessor.execute(binding, state, context, logs), - Pattern::Files(files) => files.execute(binding, state, context, logs), - Pattern::Call(pattern_call) => pattern_call.execute(binding, state, context, logs), - Pattern::Regex(regex) => regex.execute(binding, state, context, logs), - Pattern::File(file_pattern) => file_pattern.execute(binding, state, context, logs), - Pattern::Bubble(pattern_call) => pattern_call.execute(binding, state, context, logs), - Pattern::Limit(limit) => limit.execute(binding, state, context, logs), + Pattern::ASTNode(ast_node) => ast_node.execute(binding, state, context, logs).await, + Pattern::Some(some) => some.execute(binding, state, context, logs).await, + Pattern::Every(every) => every.execute(binding, state, context, logs).await, + Pattern::List(patterns) => patterns.execute(binding, state, context, logs).await, + Pattern::ListIndex(index) => index.execute(binding, state, context, logs).await, + Pattern::Map(map) => map.execute(binding, state, context, logs).await, + Pattern::Accessor(accessor) => accessor.execute(binding, state, context, logs).await, + Pattern::Files(files) => files.execute(binding, state, context, logs).await, + Pattern::Call(pattern_call) => { + pattern_call.execute(binding, state, context, logs).await + } + Pattern::Regex(regex) => regex.execute(binding, state, context, logs).await, + Pattern::File(file_pattern) => { + file_pattern.execute(binding, state, context, logs).await + } + Pattern::Bubble(pattern_call) => { + pattern_call.execute(binding, state, context, logs).await + } + Pattern::Limit(limit) => limit.execute(binding, state, context, logs).await, Pattern::CallBuiltIn(_) => bail!("CallBuiltIn cannot be executed at the moment"), Pattern::CallFunction(_) => { bail!("CallFunction cannot be executed at the moment") @@ -1106,53 +1115,63 @@ impl Matcher for Pattern { Pattern::CallForeignFunction(_) => { bail!("CallForeignFunction cannot be executed at the moment") } - Pattern::Assignment(assignment) => assignment.execute(binding, state, context, logs), - Pattern::Accumulate(accumulate) => accumulate.execute(binding, state, context, logs), + Pattern::Assignment(assignment) => { + assignment.execute(binding, state, context, logs).await + } + Pattern::Accumulate(accumulate) => { + accumulate.execute(binding, state, context, logs).await + } Pattern::StringConstant(string_constant) => { - string_constant.execute(binding, state, context, logs) + string_constant.execute(binding, state, context, logs).await + } + Pattern::AstLeafNode(leaf_node) => { + leaf_node.execute(binding, state, context, logs).await } - Pattern::AstLeafNode(leaf_node) => leaf_node.execute(binding, state, context, logs), Pattern::IntConstant(int_constant) => { - int_constant.execute(binding, state, context, logs) + int_constant.execute(binding, state, context, logs).await } Pattern::FloatConstant(double_constant) => { - double_constant.execute(binding, state, context, logs) + double_constant.execute(binding, state, context, logs).await } Pattern::BooleanConstant(boolean_constant) => { - boolean_constant.execute(binding, state, context, logs) + boolean_constant + .execute(binding, state, context, logs) + .await } - Pattern::Variable(variable) => variable.execute(binding, state, context, logs), - Pattern::Add(add) => add.execute(binding, state, context, logs), - Pattern::Subtract(subtract) => subtract.execute(binding, state, context, logs), - Pattern::Multiply(multiply) => multiply.execute(binding, state, context, logs), - Pattern::Divide(divide) => divide.execute(binding, state, context, logs), - Pattern::Modulo(modulo) => modulo.execute(binding, state, context, logs), - Pattern::And(and) => and.execute(binding, state, context, logs), - Pattern::Or(or) => or.execute(binding, state, context, logs), - Pattern::Maybe(maybe) => maybe.execute(binding, state, context, logs), - Pattern::Any(any) => any.execute(binding, state, context, logs), + Pattern::Variable(variable) => variable.execute(binding, state, context, logs).await, + Pattern::Add(add) => add.execute(binding, state, context, logs).await, + Pattern::Subtract(subtract) => subtract.execute(binding, state, context, logs).await, + Pattern::Multiply(multiply) => multiply.execute(binding, state, context, logs).await, + Pattern::Divide(divide) => divide.execute(binding, state, context, logs).await, + Pattern::Modulo(modulo) => modulo.execute(binding, state, context, logs).await, + Pattern::And(and) => and.execute(binding, state, context, logs).await, + Pattern::Or(or) => or.execute(binding, state, context, logs).await, + Pattern::Maybe(maybe) => maybe.execute(binding, state, context, logs).await, + Pattern::Any(any) => any.execute(binding, state, context, logs).await, Pattern::CodeSnippet(code_snippet) => { - code_snippet.execute(binding, state, context, logs) + code_snippet.execute(binding, state, context, logs).await } - Pattern::Rewrite(rewrite) => rewrite.execute(binding, state, context, logs), - Pattern::Log(log) => log.execute(binding, state, context, logs), - Pattern::Range(range) => range.execute(binding, state, context, logs), - Pattern::Contains(contains) => contains.execute(binding, state, context, logs), - Pattern::Includes(includes) => includes.execute(binding, state, context, logs), - Pattern::Within(within) => within.execute(binding, state, context, logs), - Pattern::After(after) => after.execute(binding, state, context, logs), - Pattern::Before(before) => before.execute(binding, state, context, logs), - Pattern::Where(where_) => where_.execute(binding, state, context, logs), + Pattern::Rewrite(rewrite) => rewrite.execute(binding, state, context, logs).await, + Pattern::Log(log) => log.execute(binding, state, context, logs).await, + Pattern::Range(range) => range.execute(binding, state, context, logs).await, + Pattern::Contains(contains) => contains.execute(binding, state, context, logs).await, + Pattern::Includes(includes) => includes.execute(binding, state, context, logs).await, + Pattern::Within(within) => within.execute(binding, state, context, logs).await, + Pattern::After(after) => after.execute(binding, state, context, logs).await, + Pattern::Before(before) => before.execute(binding, state, context, logs).await, + Pattern::Where(where_) => where_.execute(binding, state, context, logs).await, Pattern::Undefined => Undefined::execute(binding, state, context, logs), Pattern::Top => Ok(true), Pattern::Underscore => Ok(true), Pattern::Bottom => Ok(false), - Pattern::Not(not) => not.execute(binding, state, context, logs), - Pattern::If(if_) => if_.execute(binding, state, context, logs), + Pattern::Not(not) => not.execute(binding, state, context, logs).await, + Pattern::If(if_) => if_.execute(binding, state, context, logs).await, Pattern::Dots => bail!("Dots should only be directly within a list pattern."), - Pattern::Dynamic(pattern) => pattern.execute(binding, state, context, logs), - Pattern::Sequential(sequential) => sequential.execute(binding, state, context, logs), - Pattern::Like(like) => like.execute(binding, state, context, logs), + Pattern::Dynamic(pattern) => pattern.execute(binding, state, context, logs).await, + Pattern::Sequential(sequential) => { + sequential.execute(binding, state, context, logs).await + } + Pattern::Like(like) => like.execute(binding, state, context, logs).await, } } } diff --git a/crates/core/src/pattern/predicate_definition.rs b/crates/core/src/pattern/predicate_definition.rs index 59734b716..df83ca9e9 100644 --- a/crates/core/src/pattern/predicate_definition.rs +++ b/crates/core/src/pattern/predicate_definition.rs @@ -95,7 +95,7 @@ impl PredicateDefinition { Ok(()) } - pub fn call<'a>( + pub async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, @@ -103,7 +103,7 @@ impl PredicateDefinition { logs: &mut AnalysisLogs, ) -> Result { state.reset_vars(self.scope, args); - let res = self.predicate.execute_func(state, context, logs)?; + let res = self.predicate.execute_func(state, context, logs).await?; Ok(res.predicator) } } diff --git a/crates/core/src/pattern/predicate_return.rs b/crates/core/src/pattern/predicate_return.rs index 372c09723..688120d67 100644 --- a/crates/core/src/pattern/predicate_return.rs +++ b/crates/core/src/pattern/predicate_return.rs @@ -49,13 +49,13 @@ impl PrReturn { } impl Evaluator for PrReturn { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let resolved = ResolvedPattern::from_pattern(&self.pattern, state, context, logs)?; + let resolved = ResolvedPattern::from_pattern(&self.pattern, state, context, logs).await?; Ok(FuncEvaluation { predicator: false, ret_val: Some(resolved), diff --git a/crates/core/src/pattern/predicates.rs b/crates/core/src/pattern/predicates.rs index 153f78b23..87de51bd0 100644 --- a/crates/core/src/pattern/predicates.rs +++ b/crates/core/src/pattern/predicates.rs @@ -225,22 +225,24 @@ impl Name for Predicate { } impl Evaluator for Predicate { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { match self { - Predicate::Call(call) => call.execute_func(state, context, logs), - Predicate::Or(or) => or.execute_func(state, context, logs), - Predicate::And(and) => and.execute_func(state, context, logs), - Predicate::Maybe(maybe) => maybe.execute_func(state, context, logs), - Predicate::Any(any) => any.execute_func(state, context, logs), - Predicate::Rewrite(rewrite) => rewrite.execute_func(state, context, logs), - Predicate::Log(log) => log.execute_func(state, context, logs), - Predicate::Match(match_) => match_.execute_func(state, context, logs), - Predicate::Equal(equal) => equal.execute_func(state, context, logs), + Predicate::Call(call) => Box::pin(call.execute_func(state, context, logs)).await, + Predicate::Or(or) => Box::pin(or.execute_func(state, context, logs)).await, + Predicate::And(and) => Box::pin(and.execute_func(state, context, logs)).await, + Predicate::Maybe(maybe) => Box::pin(maybe.execute_func(state, context, logs)).await, + Predicate::Any(any) => Box::pin(any.execute_func(state, context, logs)).await, + Predicate::Rewrite(rewrite) => { + Box::pin(rewrite.execute_func(state, context, logs)).await + } + Predicate::Log(log) => Box::pin(log.execute_func(state, context, logs)).await, + Predicate::Match(match_) => Box::pin(match_.execute_func(state, context, logs)).await, + Predicate::Equal(equal) => Box::pin(equal.execute_func(state, context, logs)).await, Predicate::True => Ok(FuncEvaluation { predicator: true, ret_val: None, @@ -249,11 +251,17 @@ impl Evaluator for Predicate { predicator: false, ret_val: None, }), - Predicate::Not(not) => not.execute_func(state, context, logs), - Predicate::If(if_) => if_.execute_func(state, context, logs), - Predicate::Assignment(assignment) => assignment.execute_func(state, context, logs), - Predicate::Accumulate(accumulate) => accumulate.execute_func(state, context, logs), - Predicate::Return(return_) => return_.execute_func(state, context, logs), + Predicate::Not(not) => Box::pin(not.execute_func(state, context, logs)).await, + Predicate::If(if_) => Box::pin(if_.execute_func(state, context, logs)).await, + Predicate::Assignment(assignment) => { + Box::pin(assignment.execute_func(state, context, logs)).await + } + Predicate::Accumulate(accumulate) => { + Box::pin(accumulate.execute_func(state, context, logs)).await + } + Predicate::Return(return_) => { + Box::pin(return_.execute_func(state, context, logs)).await + } } } } diff --git a/crates/core/src/pattern/range.rs b/crates/core/src/pattern/range.rs index 00176fb7f..64b2ab0d8 100644 --- a/crates/core/src/pattern/range.rs +++ b/crates/core/src/pattern/range.rs @@ -85,7 +85,7 @@ impl From for Range { } impl Matcher for Range { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, _state: &mut state::State<'a>, diff --git a/crates/core/src/pattern/regex.rs b/crates/core/src/pattern/regex.rs index 9c905a1f4..0bbafd824 100644 --- a/crates/core/src/pattern/regex.rs +++ b/crates/core/src/pattern/regex.rs @@ -131,7 +131,7 @@ impl RegexPattern { )))) } - pub(crate) fn execute_matching<'a>( + pub(crate) async fn execute_matching<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -146,7 +146,7 @@ impl RegexPattern { false => regex.to_string(), }, RegexLike::Pattern(ref pattern) => { - let resolved = ResolvedPattern::from_pattern(pattern, state, context, logs)?; + let resolved = ResolvedPattern::from_pattern(pattern, state, context, logs).await?; let text = resolved.text(&state.files)?; match must_match_entire_string { true => format!("^{}$", text), @@ -211,7 +211,7 @@ impl RegexPattern { ResolvedPattern::from_string(value.to_string()) }; if let Some(pattern) = variable_content.pattern { - if !pattern.execute(&res, state, context, logs)? { + if !pattern.execute(&res, state, context, logs).await? { return Ok(false); } } @@ -232,7 +232,7 @@ impl Name for RegexPattern { } impl Matcher for RegexPattern { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -240,5 +240,6 @@ impl Matcher for RegexPattern { logs: &mut AnalysisLogs, ) -> Result { self.execute_matching(binding, state, context, logs, true) + .await } } diff --git a/crates/core/src/pattern/resolved_pattern.rs b/crates/core/src/pattern/resolved_pattern.rs index 0dba60ac0..08b767a15 100644 --- a/crates/core/src/pattern/resolved_pattern.rs +++ b/crates/core/src/pattern/resolved_pattern.rs @@ -501,7 +501,7 @@ impl<'a> ResolvedPattern<'a> { } } - pub fn from_dynamic_snippet( + pub async fn from_dynamic_snippet( snippet: &'a DynamicSnippet, state: &mut State<'a>, context: &'a impl Context, @@ -520,7 +520,7 @@ impl<'a> ResolvedPattern<'a> { let value = if let Some(value) = &content.value { value.clone() } else if let Some(pattern) = content.pattern { - Self::from_pattern(pattern, state, context, logs)? + Self::from_pattern(pattern, state, context, logs).await? } else { bail!( "cannot create resolved snippet from unresolved variable {}", @@ -535,7 +535,7 @@ impl<'a> ResolvedPattern<'a> { Ok(Self::Snippets(parts.into())) } - pub fn from_dynamic_pattern( + pub async fn from_dynamic_pattern( pattern: &'a DynamicPattern, state: &mut State<'a>, context: &'a impl Context, @@ -549,7 +549,7 @@ impl<'a> ResolvedPattern<'a> { if let Some(value) = &content.value { Ok(value.clone()) } else if let Some(pattern) = content.pattern { - Self::from_pattern(pattern, state, context, logs) + Self::from_pattern(pattern, state, context, logs).await } else { bail!( "cannot create resolved snippet from unresolved variable {}", @@ -558,26 +558,30 @@ impl<'a> ResolvedPattern<'a> { } } DynamicPattern::Accessor(accessor) => { - Self::from_accessor(accessor, state, context, logs) + Self::from_accessor(accessor, state, context, logs).await + } + DynamicPattern::ListIndex(index) => { + Self::from_list_index(index, state, context, logs).await } - DynamicPattern::ListIndex(index) => Self::from_list_index(index, state, context, logs), DynamicPattern::List(list) => { let mut elements = Vec::new(); for element in &list.elements { - elements.push(Self::from_dynamic_pattern(element, state, context, logs)?); + elements.push( + Box::pin(Self::from_dynamic_pattern(element, state, context, logs)).await?, + ); } Ok(Self::List(elements.into())) } DynamicPattern::Snippet(snippet) => { - Self::from_dynamic_snippet(snippet, state, context, logs) + Self::from_dynamic_snippet(snippet, state, context, logs).await } - DynamicPattern::CallBuiltIn(built_in) => built_in.call(state, context, logs), - DynamicPattern::CallFunction(func) => func.call(state, context, logs), - DynamicPattern::CallForeignFunction(func) => func.call(state, context, logs), + DynamicPattern::CallBuiltIn(built_in) => built_in.call(state, context, logs).await, + DynamicPattern::CallFunction(func) => func.call(state, context, logs).await, + DynamicPattern::CallForeignFunction(func) => func.call(state, context, logs).await, } } - pub(crate) fn from_accessor( + pub(crate) async fn from_accessor( accessor: &'a Accessor, state: &mut State<'a>, context: &'a impl Context, @@ -585,7 +589,7 @@ impl<'a> ResolvedPattern<'a> { ) -> Result { match accessor.get(state)? { Some(PatternOrResolved::Pattern(pattern)) => { - ResolvedPattern::from_pattern(pattern, state, context, logs) + ResolvedPattern::from_pattern(pattern, state, context, logs).await } Some(PatternOrResolved::ResolvedBinding(resolved)) => Ok(resolved), Some(PatternOrResolved::Resolved(resolved)) => Ok(resolved.clone()), @@ -593,7 +597,7 @@ impl<'a> ResolvedPattern<'a> { } } - pub(crate) fn from_list_index( + pub(crate) async fn from_list_index( index: &'a ListIndex, state: &mut State<'a>, context: &'a impl Context, @@ -601,7 +605,7 @@ impl<'a> ResolvedPattern<'a> { ) -> Result { match index.get(state)? { Some(PatternOrResolved::Pattern(pattern)) => { - ResolvedPattern::from_pattern(pattern, state, context, logs) + ResolvedPattern::from_pattern(pattern, state, context, logs).await } Some(PatternOrResolved::ResolvedBinding(resolved)) => Ok(resolved), Some(PatternOrResolved::Resolved(resolved)) => Ok(resolved.clone()), @@ -609,21 +613,23 @@ impl<'a> ResolvedPattern<'a> { } } - pub fn from_pattern( + pub async fn from_pattern( pattern: &'a Pattern, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { match pattern { - Pattern::Dynamic(pattern) => Self::from_dynamic_pattern(pattern, state, context, logs), + Pattern::Dynamic(pattern) => { + Box::pin(Self::from_dynamic_pattern(pattern, state, context, logs)).await + } Pattern::CodeSnippet(CodeSnippet { dynamic_snippet: Some(pattern), .. - }) => Self::from_dynamic_pattern(pattern, state, context, logs), - Pattern::CallBuiltIn(built_in) => built_in.call(state, context, logs), - Pattern::CallFunction(func) => func.call(state, context, logs), - Pattern::CallForeignFunction(func) => func.call(state, context, logs), + }) => Box::pin(Self::from_dynamic_pattern(pattern, state, context, logs)).await, + Pattern::CallBuiltIn(built_in) => built_in.call(state, context, logs).await, + Pattern::CallFunction(func) => func.call(state, context, logs).await, + Pattern::CallForeignFunction(func) => Box::pin(func.call(state, context, logs)).await, Pattern::StringConstant(string) => Ok(Self::Snippets(vector![ResolvedSnippet::Text( (&string.text).into(), )])), @@ -643,7 +649,7 @@ impl<'a> ResolvedPattern<'a> { if let Some(value) = &content.value { Ok(value.clone()) } else if let Some(pattern) = content.pattern { - Self::from_pattern(pattern, state, context, logs) + Box::pin(Self::from_pattern(pattern, state, context, logs)).await } else { bail!( "cannot create resolved snippet from unresolved variable {}", @@ -651,45 +657,60 @@ impl<'a> ResolvedPattern<'a> { ) } } - Pattern::List(list) => list - .patterns - .iter() - .map(|pattern| Self::from_pattern(pattern, state, context, logs)) - .collect::>>() - .map(Self::List), - Pattern::ListIndex(index) => Self::from_list_index(index, state, context, logs), - Pattern::Map(map) => map - .elements - .iter() - .map(|(key, value)| { - Ok(( - key.clone(), - Self::from_pattern(value, state, context, logs)?, - )) - }) - .collect::>>() - .map(Self::Map), - Pattern::Accessor(accessor) => Self::from_accessor(accessor, state, context, logs), + Pattern::List(list) => { + let mut resolved_patterns = Vec::with_capacity(list.patterns.len()); + for pattern in &list.patterns { + let resolved = + Box::pin(Self::from_pattern(pattern, state, context, logs)).await?; + resolved_patterns.push(resolved); + } + Ok(Self::List(resolved_patterns.into())) + } + Pattern::ListIndex(index) => { + Box::pin(Self::from_list_index(index, state, context, logs)).await + } + Pattern::Map(map) => { + let mut resolved_map = BTreeMap::new(); + for (key, value) in &map.elements { + let resolved_value = + Box::pin(Self::from_pattern(value, state, context, logs)).await?; + resolved_map.insert(key.clone(), resolved_value); + } + Ok(Self::Map(resolved_map)) + } + Pattern::Accessor(accessor) => { + Box::pin(Self::from_accessor(accessor, state, context, logs)).await + } Pattern::File(file_pattern) => { let name = &file_pattern.name; let body = &file_pattern.body; - let name = ResolvedPattern::from_pattern(name, state, context, logs)?; + let name = + Box::pin(ResolvedPattern::from_pattern(name, state, context, logs)).await?; let name = name.text(&state.files)?; let name = ResolvedPattern::Constant(Constant::String(name.to_string())); - let body = ResolvedPattern::from_pattern(body, state, context, logs)?; + let body = + Box::pin(ResolvedPattern::from_pattern(body, state, context, logs)).await?; // todo: replace GENERATED_SOURCE with a computed source once linearization and // on-the-fly rewrites are in place Ok(ResolvedPattern::File(File::Resolved(Box::new( ResolvedFile { name, body }, )))) } - Pattern::Add(add_pattern) => add_pattern.call(state, context, logs), - Pattern::Subtract(subtract_pattern) => subtract_pattern.call(state, context, logs), - Pattern::Multiply(multiply_pattern) => multiply_pattern.call(state, context, logs), - Pattern::Divide(divide_pattern) => divide_pattern.call(state, context, logs), - Pattern::Modulo(modulo_pattern) => modulo_pattern.call(state, context, logs), - Pattern::Before(before) => before.prev_pattern(state, context, logs), - Pattern::After(after) => after.next_pattern(state, context, logs), + Pattern::Add(add_pattern) => Box::pin(add_pattern.call(state, context, logs)).await, + Pattern::Subtract(subtract_pattern) => { + Box::pin(subtract_pattern.call(state, context, logs)).await + } + Pattern::Multiply(multiply_pattern) => { + Box::pin(multiply_pattern.call(state, context, logs)).await + } + Pattern::Divide(divide_pattern) => { + Box::pin(divide_pattern.call(state, context, logs)).await + } + Pattern::Modulo(modulo_pattern) => { + Box::pin(modulo_pattern.call(state, context, logs)).await + } + Pattern::Before(before) => Box::pin(before.prev_pattern(state, context, logs)).await, + Pattern::After(after) => Box::pin(after.next_pattern(state, context, logs)).await, Pattern::ASTNode(_) | Pattern::CodeSnippet(_) | Pattern::Call(_) @@ -977,13 +998,13 @@ impl<'a> ResolvedPattern<'a> { } } -pub(crate) fn pattern_to_binding<'a>( +pub(crate) async fn pattern_to_binding<'a>( pattern: &'a Pattern, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let resolved = ResolvedPattern::from_pattern(pattern, state, context, logs)?; + let resolved = ResolvedPattern::from_pattern(pattern, state, context, logs).await?; if let ResolvedPattern::Binding(binding) = resolved { Ok(binding .last() @@ -996,21 +1017,23 @@ pub(crate) fn pattern_to_binding<'a>( // borrow here seems off I think we want Vec<&ResolvedPattern> // since we'll be getting pointers to var_content -pub fn patterns_to_resolved<'a>( +pub async fn patterns_to_resolved<'a>( patterns: &'a [Option], state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result>>> { - patterns - .iter() - .map(|p| match p { - Some(pattern) => Ok(Some(ResolvedPattern::from_pattern( - pattern, state, context, logs, - )?)), - None => Ok(None), - }) - .collect::>>() + let mut resolved_patterns = Vec::with_capacity(patterns.len()); + for p in patterns { + let resolved = match p { + Some(pattern) => { + Some(ResolvedPattern::from_pattern(pattern, state, context, logs).await?) + } + None => None, + }; + resolved_patterns.push(resolved); + } + Ok(resolved_patterns) } /* diff --git a/crates/core/src/pattern/rewrite.rs b/crates/core/src/pattern/rewrite.rs index f6160b549..6963abffc 100644 --- a/crates/core/src/pattern/rewrite.rs +++ b/crates/core/src/pattern/rewrite.rs @@ -176,7 +176,7 @@ impl Rewrite { * * If called from a rewrite pattern, the binding should be Some(the current node). */ - pub(crate) fn execute_generalized<'a>( + async fn execute_generalized<'a>( &'a self, resolved: Option<&ResolvedPattern<'a>>, state: &mut State<'a>, @@ -185,7 +185,7 @@ impl Rewrite { ) -> Result { let resolved = match resolved { Some(b) => { - if !self.left.execute(b, state, context, logs)? { + if !self.left.execute(b, state, context, logs).await? { return Ok(false); } else { Cow::Borrowed(b) @@ -235,7 +235,7 @@ impl Rewrite { } }; let replacement: ResolvedPattern<'_> = - ResolvedPattern::from_dynamic_pattern(&self.right, state, context, logs)?; + ResolvedPattern::from_dynamic_pattern(&self.right, state, context, logs).await?; let effects = bindings.iter().map(|b| Effect { binding: b.clone(), pattern: replacement.clone(), @@ -253,7 +253,7 @@ impl Name for Rewrite { } impl Matcher for Rewrite { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -261,17 +261,18 @@ impl Matcher for Rewrite { logs: &mut AnalysisLogs, ) -> Result { self.execute_generalized(Some(binding), state, context, logs) + .await } } impl Evaluator for Rewrite { - fn execute_func<'a>( + async fn execute_func<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let predicator = self.execute_generalized(None, state, context, logs)?; + let predicator = self.execute_generalized(None, state, context, logs).await?; Ok(FuncEvaluation { predicator, ret_val: None, diff --git a/crates/core/src/pattern/sequential.rs b/crates/core/src/pattern/sequential.rs index 7451c49d1..4531965a2 100644 --- a/crates/core/src/pattern/sequential.rs +++ b/crates/core/src/pattern/sequential.rs @@ -82,7 +82,7 @@ impl Sequential { } impl Matcher for Sequential { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -90,7 +90,7 @@ impl Matcher for Sequential { logs: &mut AnalysisLogs, ) -> Result { for step in &self.0 { - if !step.execute(binding, state, context, logs)? { + if !step.execute(binding, state, context, logs).await? { return Ok(false); } } diff --git a/crates/core/src/pattern/some.rs b/crates/core/src/pattern/some.rs index a8d3202e6..71095ecc4 100644 --- a/crates/core/src/pattern/some.rs +++ b/crates/core/src/pattern/some.rs @@ -55,7 +55,7 @@ impl Name for Some { } impl Matcher for Some { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -73,12 +73,16 @@ impl Matcher for Some { let mut cur_state = init_state.clone(); for item in list_items { let state = cur_state.clone(); - if self.pattern.execute( - &ResolvedPattern::from_node(item), - &mut cur_state, - context, - logs, - )? { + if self + .pattern + .execute( + &ResolvedPattern::from_node(item), + &mut cur_state, + context, + logs, + ) + .await? + { did_match = true; } else { cur_state = state; @@ -93,7 +97,10 @@ impl Matcher for Some { let mut did_match = false; for element in elements { let state = cur_state.clone(); - if pattern.execute(element, &mut cur_state, context, logs)? { + if pattern + .execute(element, &mut cur_state, context, logs) + .await? + { did_match = true; } else { cur_state = state; @@ -111,7 +118,10 @@ impl Matcher for Some { let key = ResolvedPattern::Constant(crate::binding::Constant::String(key.clone())); let resolved = ResolvedPattern::List(vector![key, value.clone()]); - if pattern.execute(&resolved, &mut cur_state, context, logs)? { + if pattern + .execute(&resolved, &mut cur_state, context, logs) + .await? + { did_match = true; } else { cur_state = state; diff --git a/crates/core/src/pattern/step.rs b/crates/core/src/pattern/step.rs index 85be7aa95..fa8d2895a 100644 --- a/crates/core/src/pattern/step.rs +++ b/crates/core/src/pattern/step.rs @@ -185,7 +185,7 @@ fn extract_file_pointers(binding: &ResolvedPattern) -> Option> { } impl Matcher for Step { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -214,7 +214,7 @@ impl Matcher for Step { .collect(), ))) }; - if !self.pattern.execute(&binding, state, context, logs)? { + if !self.pattern.execute(&binding, state, context, logs).await? { return Ok(false); } diff --git a/crates/core/src/pattern/string_constant.rs b/crates/core/src/pattern/string_constant.rs index e154c54ca..7cf10525a 100644 --- a/crates/core/src/pattern/string_constant.rs +++ b/crates/core/src/pattern/string_constant.rs @@ -38,7 +38,7 @@ impl Name for StringConstant { // this does what a raw string should do // TODO: rename this, and implement StringConstant that checks sort. impl Matcher for StringConstant { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -82,7 +82,7 @@ impl Name for AstLeafNode { } impl Matcher for AstLeafNode { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, _state: &mut State<'a>, diff --git a/crates/core/src/pattern/subtract.rs b/crates/core/src/pattern/subtract.rs index 687eda2d1..a75cf41e9 100644 --- a/crates/core/src/pattern/subtract.rs +++ b/crates/core/src/pattern/subtract.rs @@ -62,24 +62,24 @@ impl Subtract { Ok(Self::new(left, right)) } - pub(crate) fn call<'a>( + pub(crate) async fn call<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result> { - let res = self.evaluate(state, context, logs)?; + let res = self.evaluate(state, context, logs).await?; Ok(ResolvedPattern::Constant(Constant::Float(res))) } - fn evaluate<'a>( + async fn evaluate<'a>( &'a self, state: &mut State<'a>, context: &'a impl Context, logs: &mut AnalysisLogs, ) -> Result { - let lhs = self.lhs.float(state, context, logs)?; - let rhs = self.rhs.float(state, context, logs)?; + let lhs = self.lhs.float(state, context, logs).await?; + let rhs = self.rhs.float(state, context, logs).await?; let res = lhs - rhs; Ok(res) } @@ -92,7 +92,7 @@ impl Name for Subtract { } impl Matcher for Subtract { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -101,7 +101,7 @@ impl Matcher for Subtract { ) -> Result { let binding_text = binding.text(&state.files)?; let binding_int = binding_text.parse::()?; - let target = self.evaluate(state, context, logs)?; + let target = self.evaluate(state, context, logs).await?; Ok(binding_int == target) } } diff --git a/crates/core/src/pattern/variable.rs b/crates/core/src/pattern/variable.rs index cf05bc473..0be22bdee 100644 --- a/crates/core/src/pattern/variable.rs +++ b/crates/core/src/pattern/variable.rs @@ -309,7 +309,7 @@ impl Name for Variable { } impl Matcher for Variable { - fn execute<'a>( + async fn execute<'a>( &'a self, resolved_pattern: &ResolvedPattern<'a>, state: &mut State<'a>, @@ -333,7 +333,10 @@ impl Matcher for Variable { .get_mut(self.index) .unwrap()); if let Some(pattern) = variable_content.pattern { - if !pattern.execute(resolved_pattern, state, context, logs)? { + if !pattern + .execute(resolved_pattern, state, context, logs) + .await? + { return Ok(false); } } diff --git a/crates/core/src/pattern/where.rs b/crates/core/src/pattern/where.rs index a208eb4b6..1bcb46c04 100644 --- a/crates/core/src/pattern/where.rs +++ b/crates/core/src/pattern/where.rs @@ -150,7 +150,7 @@ impl Name for Where { impl Matcher for Where { // order here is pattern then side condition, do we prefer side condition then pattern? // should the state be reset on failure? - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -160,13 +160,15 @@ impl Matcher for Where { let mut cur_state = init_state.clone(); if !self .pattern - .execute(binding, &mut cur_state, context, logs)? + .execute(binding, &mut cur_state, context, logs) + .await? { return Ok(false); } if self .side_condition - .execute_func(&mut cur_state, context, logs)? + .execute_func(&mut cur_state, context, logs) + .await? .predicator { *init_state = cur_state; diff --git a/crates/core/src/pattern/within.rs b/crates/core/src/pattern/within.rs index 33b0c4d59..dc3a7c3ca 100644 --- a/crates/core/src/pattern/within.rs +++ b/crates/core/src/pattern/within.rs @@ -56,7 +56,7 @@ impl Name for Within { } impl Matcher for Within { - fn execute<'a>( + async fn execute<'a>( &'a self, binding: &ResolvedPattern<'a>, init_state: &mut State<'a>, @@ -69,7 +69,8 @@ impl Matcher for Within { let state = cur_state.clone(); if self .pattern - .execute(binding, &mut cur_state, context, logs)? + .execute(binding, &mut cur_state, context, logs) + .await? { did_match = true; } else { @@ -87,12 +88,16 @@ impl Matcher for Within { }; for n in node.ancestors() { let state = cur_state.clone(); - if self.pattern.execute( - &ResolvedPattern::from_node(n), - &mut cur_state, - context, - logs, - )? { + if self + .pattern + .execute( + &ResolvedPattern::from_node(n), + &mut cur_state, + context, + logs, + ) + .await? + { did_match = true; } else { cur_state = state;