Replace FunctionContext with Evaluator (#2048)

This commit is contained in:
Casey Rodarmor 2024-05-17 17:21:47 -07:00 committed by GitHub
parent 843286f27c
commit 7359deeb99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 121 additions and 148 deletions

View File

@ -1,12 +1,12 @@
use super::*; use super::*;
pub(crate) struct Evaluator<'src: 'run, 'run> { pub(crate) struct Evaluator<'src: 'run, 'run> {
assignments: Option<&'run Table<'src, Assignment<'src>>>, pub(crate) assignments: Option<&'run Table<'src, Assignment<'src>>>,
config: &'run Config, pub(crate) config: &'run Config,
dotenv: &'run BTreeMap<String, String>, pub(crate) dotenv: &'run BTreeMap<String, String>,
scope: Scope<'src, 'run>, pub(crate) scope: Scope<'src, 'run>,
settings: &'run Settings<'run>, pub(crate) settings: &'run Settings<'run>,
search: &'run Search, pub(crate) search: &'run Search,
} }
impl<'src, 'run> Evaluator<'src, 'run> { impl<'src, 'run> Evaluator<'src, 'run> {
@ -68,30 +68,23 @@ impl<'src, 'run> Evaluator<'src, 'run> {
Expression::Call { thunk } => { Expression::Call { thunk } => {
use Thunk::*; use Thunk::*;
let context = FunctionContext {
dotenv: self.dotenv,
invocation_directory: &self.config.invocation_directory,
search: self.search,
};
match thunk { match thunk {
Nullary { name, function, .. } => { Nullary { name, function, .. } => function(self).map_err(|message| Error::FunctionCall {
function(&context).map_err(|message| Error::FunctionCall { function: *name,
function: *name, message,
message, }),
})
}
Unary { Unary {
name, name,
function, function,
arg, arg,
.. ..
} => function(&context, &self.evaluate_expression(arg)?).map_err(|message| { } => {
Error::FunctionCall { let arg = self.evaluate_expression(arg)?;
function(self, &arg).map_err(|message| Error::FunctionCall {
function: *name, function: *name,
message, message,
} })
}), }
UnaryOpt { UnaryOpt {
name, name,
function, function,
@ -104,7 +97,7 @@ impl<'src, 'run> Evaluator<'src, 'run> {
None => None, None => None,
}; };
function(&context, &a, b.as_deref()).map_err(|message| Error::FunctionCall { function(self, &a, b.as_deref()).map_err(|message| Error::FunctionCall {
function: *name, function: *name,
message, message,
}) })
@ -114,15 +107,14 @@ impl<'src, 'run> Evaluator<'src, 'run> {
function, function,
args: [a, b], args: [a, b],
.. ..
} => function( } => {
&context, let a = self.evaluate_expression(a)?;
&self.evaluate_expression(a)?, let b = self.evaluate_expression(b)?;
&self.evaluate_expression(b)?, function(self, &a, &b).map_err(|message| Error::FunctionCall {
) function: *name,
.map_err(|message| Error::FunctionCall { message,
function: *name, })
message, }
}),
BinaryPlus { BinaryPlus {
name, name,
function, function,
@ -131,13 +123,12 @@ impl<'src, 'run> Evaluator<'src, 'run> {
} => { } => {
let a = self.evaluate_expression(a)?; let a = self.evaluate_expression(a)?;
let b = self.evaluate_expression(b)?; let b = self.evaluate_expression(b)?;
let mut rest_evaluated = Vec::new(); let mut rest_evaluated = Vec::new();
for arg in rest { for arg in rest {
rest_evaluated.push(self.evaluate_expression(arg)?); rest_evaluated.push(self.evaluate_expression(arg)?);
} }
function(&context, &a, &b, &rest_evaluated).map_err(|message| Error::FunctionCall { function(self, &a, &b, &rest_evaluated).map_err(|message| Error::FunctionCall {
function: *name, function: *name,
message, message,
}) })
@ -147,16 +138,15 @@ impl<'src, 'run> Evaluator<'src, 'run> {
function, function,
args: [a, b, c], args: [a, b, c],
.. ..
} => function( } => {
&context, let a = self.evaluate_expression(a)?;
&self.evaluate_expression(a)?, let b = self.evaluate_expression(b)?;
&self.evaluate_expression(b)?, let c = self.evaluate_expression(c)?;
&self.evaluate_expression(c)?, function(self, &a, &b, &c).map_err(|message| Error::FunctionCall {
) function: *name,
.map_err(|message| Error::FunctionCall { message,
function: *name, })
message, }
}),
} }
} }
Expression::StringLiteral { string_literal } => Ok(string_literal.cooked.clone()), Expression::StringLiteral { string_literal } => Ok(string_literal.cooked.clone()),

View File

@ -9,12 +9,12 @@ use {
}; };
pub(crate) enum Function { pub(crate) enum Function {
Nullary(fn(&FunctionContext) -> Result<String, String>), Nullary(fn(&Evaluator) -> Result<String, String>),
Unary(fn(&FunctionContext, &str) -> Result<String, String>), Unary(fn(&Evaluator, &str) -> Result<String, String>),
UnaryOpt(fn(&FunctionContext, &str, Option<&str>) -> Result<String, String>), UnaryOpt(fn(&Evaluator, &str, Option<&str>) -> Result<String, String>),
Binary(fn(&FunctionContext, &str, &str) -> Result<String, String>), Binary(fn(&Evaluator, &str, &str) -> Result<String, String>),
BinaryPlus(fn(&FunctionContext, &str, &str, &[String]) -> Result<String, String>), BinaryPlus(fn(&Evaluator, &str, &str, &[String]) -> Result<String, String>),
Ternary(fn(&FunctionContext, &str, &str, &str) -> Result<String, String>), Ternary(fn(&Evaluator, &str, &str, &str) -> Result<String, String>),
} }
pub(crate) fn get(name: &str) -> Option<Function> { pub(crate) fn get(name: &str) -> Option<Function> {
@ -96,18 +96,18 @@ impl Function {
} }
} }
fn absolute_path(context: &FunctionContext, path: &str) -> Result<String, String> { fn absolute_path(evaluator: &Evaluator, path: &str) -> Result<String, String> {
let abs_path_unchecked = context.search.working_directory.join(path).lexiclean(); let abs_path_unchecked = evaluator.search.working_directory.join(path).lexiclean();
match abs_path_unchecked.to_str() { match abs_path_unchecked.to_str() {
Some(absolute_path) => Ok(absolute_path.to_owned()), Some(absolute_path) => Ok(absolute_path.to_owned()),
None => Err(format!( None => Err(format!(
"Working directory is not valid unicode: {}", "Working directory is not valid unicode: {}",
context.search.working_directory.display() evaluator.search.working_directory.display()
)), )),
} }
} }
fn append(_context: &FunctionContext, suffix: &str, s: &str) -> Result<String, String> { fn append(_evaluator: &Evaluator, suffix: &str, s: &str) -> Result<String, String> {
Ok( Ok(
s.split_whitespace() s.split_whitespace()
.map(|s| format!("{s}{suffix}")) .map(|s| format!("{s}{suffix}"))
@ -116,16 +116,16 @@ fn append(_context: &FunctionContext, suffix: &str, s: &str) -> Result<String, S
) )
} }
fn arch(_context: &FunctionContext) -> Result<String, String> { fn arch(_evaluator: &Evaluator) -> Result<String, String> {
Ok(target::arch().to_owned()) Ok(target::arch().to_owned())
} }
fn blake3(_context: &FunctionContext, s: &str) -> Result<String, String> { fn blake3(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(blake3::hash(s.as_bytes()).to_string()) Ok(blake3::hash(s.as_bytes()).to_string())
} }
fn blake3_file(context: &FunctionContext, path: &str) -> Result<String, String> { fn blake3_file(evaluator: &Evaluator, path: &str) -> Result<String, String> {
let path = context.search.working_directory.join(path); let path = evaluator.search.working_directory.join(path);
let mut hasher = blake3::Hasher::new(); let mut hasher = blake3::Hasher::new();
hasher hasher
.update_mmap_rayon(&path) .update_mmap_rayon(&path)
@ -133,7 +133,7 @@ fn blake3_file(context: &FunctionContext, path: &str) -> Result<String, String>
Ok(hasher.finalize().to_string()) Ok(hasher.finalize().to_string())
} }
fn canonicalize(_context: &FunctionContext, path: &str) -> Result<String, String> { fn canonicalize(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
let canonical = let canonical =
std::fs::canonicalize(path).map_err(|err| format!("I/O error canonicalizing path: {err}"))?; std::fs::canonicalize(path).map_err(|err| format!("I/O error canonicalizing path: {err}"))?;
@ -145,7 +145,7 @@ fn canonicalize(_context: &FunctionContext, path: &str) -> Result<String, String
}) })
} }
fn capitalize(_context: &FunctionContext, s: &str) -> Result<String, String> { fn capitalize(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
let mut capitalized = String::new(); let mut capitalized = String::new();
for (i, c) in s.chars().enumerate() { for (i, c) in s.chars().enumerate() {
if i == 0 { if i == 0 {
@ -157,7 +157,7 @@ fn capitalize(_context: &FunctionContext, s: &str) -> Result<String, String> {
Ok(capitalized) Ok(capitalized)
} }
fn clean(_context: &FunctionContext, path: &str) -> Result<String, String> { fn clean(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
Ok(Path::new(path).lexiclean().to_str().unwrap().to_owned()) Ok(Path::new(path).lexiclean().to_str().unwrap().to_owned())
} }
@ -177,10 +177,10 @@ fn dir(name: &'static str, f: fn() -> Option<PathBuf>) -> Result<String, String>
} }
} }
fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> { fn env_var(evaluator: &Evaluator, key: &str) -> Result<String, String> {
use std::env::VarError::*; use std::env::VarError::*;
if let Some(value) = context.dotenv.get(key) { if let Some(value) = evaluator.dotenv.get(key) {
return Ok(value.clone()); return Ok(value.clone());
} }
@ -193,14 +193,10 @@ fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> {
} }
} }
fn env_var_or_default( fn env_var_or_default(evaluator: &Evaluator, key: &str, default: &str) -> Result<String, String> {
context: &FunctionContext,
key: &str,
default: &str,
) -> Result<String, String> {
use std::env::VarError::*; use std::env::VarError::*;
if let Some(value) = context.dotenv.get(key) { if let Some(value) = evaluator.dotenv.get(key) {
return Ok(value.clone()); return Ok(value.clone());
} }
@ -213,60 +209,61 @@ fn env_var_or_default(
} }
} }
fn env(context: &FunctionContext, key: &str, default: Option<&str>) -> Result<String, String> { fn env(evaluator: &Evaluator, key: &str, default: Option<&str>) -> Result<String, String> {
match default { match default {
Some(val) => env_var_or_default(context, key, val), Some(val) => env_var_or_default(evaluator, key, val),
None => env_var(context, key), None => env_var(evaluator, key),
} }
} }
fn error(_context: &FunctionContext, message: &str) -> Result<String, String> { fn error(_evaluator: &Evaluator, message: &str) -> Result<String, String> {
Err(message.to_owned()) Err(message.to_owned())
} }
fn extension(_context: &FunctionContext, path: &str) -> Result<String, String> { fn extension(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
Utf8Path::new(path) Utf8Path::new(path)
.extension() .extension()
.map(str::to_owned) .map(str::to_owned)
.ok_or_else(|| format!("Could not extract extension from `{path}`")) .ok_or_else(|| format!("Could not extract extension from `{path}`"))
} }
fn file_name(_context: &FunctionContext, path: &str) -> Result<String, String> { fn file_name(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
Utf8Path::new(path) Utf8Path::new(path)
.file_name() .file_name()
.map(str::to_owned) .map(str::to_owned)
.ok_or_else(|| format!("Could not extract file name from `{path}`")) .ok_or_else(|| format!("Could not extract file name from `{path}`"))
} }
fn file_stem(_context: &FunctionContext, path: &str) -> Result<String, String> { fn file_stem(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
Utf8Path::new(path) Utf8Path::new(path)
.file_stem() .file_stem()
.map(str::to_owned) .map(str::to_owned)
.ok_or_else(|| format!("Could not extract file stem from `{path}`")) .ok_or_else(|| format!("Could not extract file stem from `{path}`"))
} }
fn invocation_directory(context: &FunctionContext) -> Result<String, String> { fn invocation_directory(evaluator: &Evaluator) -> Result<String, String> {
Platform::convert_native_path( Platform::convert_native_path(
&context.search.working_directory, &evaluator.search.working_directory,
context.invocation_directory, &evaluator.config.invocation_directory,
) )
.map_err(|e| format!("Error getting shell path: {e}")) .map_err(|e| format!("Error getting shell path: {e}"))
} }
fn invocation_directory_native(context: &FunctionContext) -> Result<String, String> { fn invocation_directory_native(evaluator: &Evaluator) -> Result<String, String> {
context evaluator
.config
.invocation_directory .invocation_directory
.to_str() .to_str()
.map(str::to_owned) .map(str::to_owned)
.ok_or_else(|| { .ok_or_else(|| {
format!( format!(
"Invocation directory is not valid unicode: {}", "Invocation directory is not valid unicode: {}",
context.invocation_directory.display() evaluator.config.invocation_directory.display()
) )
}) })
} }
fn prepend(_context: &FunctionContext, prefix: &str, s: &str) -> Result<String, String> { fn prepend(_evaluator: &Evaluator, prefix: &str, s: &str) -> Result<String, String> {
Ok( Ok(
s.split_whitespace() s.split_whitespace()
.map(|s| format!("{prefix}{s}")) .map(|s| format!("{prefix}{s}"))
@ -275,12 +272,7 @@ fn prepend(_context: &FunctionContext, prefix: &str, s: &str) -> Result<String,
) )
} }
fn join( fn join(_evaluator: &Evaluator, base: &str, with: &str, and: &[String]) -> Result<String, String> {
_context: &FunctionContext,
base: &str,
with: &str,
and: &[String],
) -> Result<String, String> {
let mut result = Utf8Path::new(base).join(with); let mut result = Utf8Path::new(base).join(with);
for arg in and { for arg in and {
result.push(arg); result.push(arg);
@ -288,7 +280,7 @@ fn join(
Ok(result.to_string()) Ok(result.to_string())
} }
fn just_executable(_context: &FunctionContext) -> Result<String, String> { fn just_executable(_evaluator: &Evaluator) -> Result<String, String> {
let exe_path = let exe_path =
env::current_exe().map_err(|e| format!("Error getting current executable: {e}"))?; env::current_exe().map_err(|e| format!("Error getting current executable: {e}"))?;
@ -300,12 +292,12 @@ fn just_executable(_context: &FunctionContext) -> Result<String, String> {
}) })
} }
fn just_pid(_context: &FunctionContext) -> Result<String, String> { fn just_pid(_evaluator: &Evaluator) -> Result<String, String> {
Ok(std::process::id().to_string()) Ok(std::process::id().to_string())
} }
fn justfile(context: &FunctionContext) -> Result<String, String> { fn justfile(evaluator: &Evaluator) -> Result<String, String> {
context evaluator
.search .search
.justfile .justfile
.to_str() .to_str()
@ -313,16 +305,16 @@ fn justfile(context: &FunctionContext) -> Result<String, String> {
.ok_or_else(|| { .ok_or_else(|| {
format!( format!(
"Justfile path is not valid unicode: {}", "Justfile path is not valid unicode: {}",
context.search.justfile.display() evaluator.search.justfile.display()
) )
}) })
} }
fn justfile_directory(context: &FunctionContext) -> Result<String, String> { fn justfile_directory(evaluator: &Evaluator) -> Result<String, String> {
let justfile_directory = context.search.justfile.parent().ok_or_else(|| { let justfile_directory = evaluator.search.justfile.parent().ok_or_else(|| {
format!( format!(
"Could not resolve justfile directory. Justfile `{}` had no parent.", "Could not resolve justfile directory. Justfile `{}` had no parent.",
context.search.justfile.display() evaluator.search.justfile.display()
) )
})?; })?;
@ -337,41 +329,41 @@ fn justfile_directory(context: &FunctionContext) -> Result<String, String> {
}) })
} }
fn kebabcase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn kebabcase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_kebab_case()) Ok(s.to_kebab_case())
} }
fn lowercamelcase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn lowercamelcase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_lower_camel_case()) Ok(s.to_lower_camel_case())
} }
fn lowercase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn lowercase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_lowercase()) Ok(s.to_lowercase())
} }
fn num_cpus(_context: &FunctionContext) -> Result<String, String> { fn num_cpus(_evaluator: &Evaluator) -> Result<String, String> {
let num = num_cpus::get(); let num = num_cpus::get();
Ok(num.to_string()) Ok(num.to_string())
} }
fn os(_context: &FunctionContext) -> Result<String, String> { fn os(_evaluator: &Evaluator) -> Result<String, String> {
Ok(target::os().to_owned()) Ok(target::os().to_owned())
} }
fn os_family(_context: &FunctionContext) -> Result<String, String> { fn os_family(_evaluator: &Evaluator) -> Result<String, String> {
Ok(target::family().to_owned()) Ok(target::family().to_owned())
} }
fn parent_directory(_context: &FunctionContext, path: &str) -> Result<String, String> { fn parent_directory(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
Utf8Path::new(path) Utf8Path::new(path)
.parent() .parent()
.map(Utf8Path::to_string) .map(Utf8Path::to_string)
.ok_or_else(|| format!("Could not extract parent directory from `{path}`")) .ok_or_else(|| format!("Could not extract parent directory from `{path}`"))
} }
fn path_exists(context: &FunctionContext, path: &str) -> Result<String, String> { fn path_exists(evaluator: &Evaluator, path: &str) -> Result<String, String> {
Ok( Ok(
context evaluator
.search .search
.working_directory .working_directory
.join(path) .join(path)
@ -380,16 +372,16 @@ fn path_exists(context: &FunctionContext, path: &str) -> Result<String, String>
) )
} }
fn quote(_context: &FunctionContext, s: &str) -> Result<String, String> { fn quote(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(format!("'{}'", s.replace('\'', "'\\''"))) Ok(format!("'{}'", s.replace('\'', "'\\''")))
} }
fn replace(_context: &FunctionContext, s: &str, from: &str, to: &str) -> Result<String, String> { fn replace(_evaluator: &Evaluator, s: &str, from: &str, to: &str) -> Result<String, String> {
Ok(s.replace(from, to)) Ok(s.replace(from, to))
} }
fn replace_regex( fn replace_regex(
_context: &FunctionContext, _evaluator: &Evaluator,
s: &str, s: &str,
regex: &str, regex: &str,
replacement: &str, replacement: &str,
@ -402,7 +394,7 @@ fn replace_regex(
) )
} }
fn sha256(_context: &FunctionContext, s: &str) -> Result<String, String> { fn sha256(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(s); hasher.update(s);
@ -410,9 +402,9 @@ fn sha256(_context: &FunctionContext, s: &str) -> Result<String, String> {
Ok(format!("{hash:x}")) Ok(format!("{hash:x}"))
} }
fn sha256_file(context: &FunctionContext, path: &str) -> Result<String, String> { fn sha256_file(evaluator: &Evaluator, path: &str) -> Result<String, String> {
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
let path = context.search.working_directory.join(path); let path = evaluator.search.working_directory.join(path);
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
let mut file = let mut file =
fs::File::open(&path).map_err(|err| format!("Failed to open `{}`: {err}", path.display()))?; fs::File::open(&path).map_err(|err| format!("Failed to open `{}`: {err}", path.display()))?;
@ -422,63 +414,63 @@ fn sha256_file(context: &FunctionContext, path: &str) -> Result<String, String>
Ok(format!("{hash:x}")) Ok(format!("{hash:x}"))
} }
fn shoutykebabcase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn shoutykebabcase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_shouty_kebab_case()) Ok(s.to_shouty_kebab_case())
} }
fn shoutysnakecase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn shoutysnakecase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_shouty_snake_case()) Ok(s.to_shouty_snake_case())
} }
fn snakecase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn snakecase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_snake_case()) Ok(s.to_snake_case())
} }
fn titlecase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn titlecase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_title_case()) Ok(s.to_title_case())
} }
fn trim(_context: &FunctionContext, s: &str) -> Result<String, String> { fn trim(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.trim().to_owned()) Ok(s.trim().to_owned())
} }
fn trim_end(_context: &FunctionContext, s: &str) -> Result<String, String> { fn trim_end(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.trim_end().to_owned()) Ok(s.trim_end().to_owned())
} }
fn trim_end_match(_context: &FunctionContext, s: &str, pat: &str) -> Result<String, String> { fn trim_end_match(_evaluator: &Evaluator, s: &str, pat: &str) -> Result<String, String> {
Ok(s.strip_suffix(pat).unwrap_or(s).to_owned()) Ok(s.strip_suffix(pat).unwrap_or(s).to_owned())
} }
fn trim_end_matches(_context: &FunctionContext, s: &str, pat: &str) -> Result<String, String> { fn trim_end_matches(_evaluator: &Evaluator, s: &str, pat: &str) -> Result<String, String> {
Ok(s.trim_end_matches(pat).to_owned()) Ok(s.trim_end_matches(pat).to_owned())
} }
fn trim_start(_context: &FunctionContext, s: &str) -> Result<String, String> { fn trim_start(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.trim_start().to_owned()) Ok(s.trim_start().to_owned())
} }
fn trim_start_match(_context: &FunctionContext, s: &str, pat: &str) -> Result<String, String> { fn trim_start_match(_evaluator: &Evaluator, s: &str, pat: &str) -> Result<String, String> {
Ok(s.strip_prefix(pat).unwrap_or(s).to_owned()) Ok(s.strip_prefix(pat).unwrap_or(s).to_owned())
} }
fn trim_start_matches(_context: &FunctionContext, s: &str, pat: &str) -> Result<String, String> { fn trim_start_matches(_evaluator: &Evaluator, s: &str, pat: &str) -> Result<String, String> {
Ok(s.trim_start_matches(pat).to_owned()) Ok(s.trim_start_matches(pat).to_owned())
} }
fn uppercamelcase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn uppercamelcase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_upper_camel_case()) Ok(s.to_upper_camel_case())
} }
fn uppercase(_context: &FunctionContext, s: &str) -> Result<String, String> { fn uppercase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
Ok(s.to_uppercase()) Ok(s.to_uppercase())
} }
fn uuid(_context: &FunctionContext) -> Result<String, String> { fn uuid(_evaluator: &Evaluator) -> Result<String, String> {
Ok(uuid::Uuid::new_v4().to_string()) Ok(uuid::Uuid::new_v4().to_string())
} }
fn without_extension(_context: &FunctionContext, path: &str) -> Result<String, String> { fn without_extension(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
let parent = Utf8Path::new(path) let parent = Utf8Path::new(path)
.parent() .parent()
.ok_or_else(|| format!("Could not extract parent from `{path}`"))?; .ok_or_else(|| format!("Could not extract parent from `{path}`"))?;
@ -493,7 +485,7 @@ fn without_extension(_context: &FunctionContext, path: &str) -> Result<String, S
/// Check whether a string processes properly as semver (e.x. "0.1.0") /// Check whether a string processes properly as semver (e.x. "0.1.0")
/// and matches a given semver requirement (e.x. ">=0.1.0") /// and matches a given semver requirement (e.x. ">=0.1.0")
fn semver_matches( fn semver_matches(
_context: &FunctionContext, _evaluator: &Evaluator,
version: &str, version: &str,
requirement: &str, requirement: &str,
) -> Result<String, String> { ) -> Result<String, String> {

View File

@ -1,7 +0,0 @@
use super::*;
pub(crate) struct FunctionContext<'run> {
pub(crate) dotenv: &'run BTreeMap<String, String>,
pub(crate) invocation_directory: &'run Path,
pub(crate) search: &'run Search,
}

View File

@ -23,12 +23,11 @@ pub(crate) use {
config_error::ConfigError, count::Count, delimiter::Delimiter, dependency::Dependency, config_error::ConfigError, count::Count, delimiter::Delimiter, dependency::Dependency,
dump_format::DumpFormat, enclosure::Enclosure, error::Error, evaluator::Evaluator, dump_format::DumpFormat, enclosure::Enclosure, error::Error, evaluator::Evaluator,
expression::Expression, fragment::Fragment, function::Function, expression::Expression, fragment::Fragment, function::Function,
function_context::FunctionContext, interrupt_guard::InterruptGuard, interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
interrupt_handler::InterruptHandler, item::Item, justfile::Justfile, keyed::Keyed, justfile::Justfile, keyed::Keyed, keyword::Keyword, lexer::Lexer, line::Line, list::List,
keyword::Keyword, lexer::Lexer, line::Line, list::List, load_dotenv::load_dotenv, load_dotenv::load_dotenv, loader::Loader, name::Name, namepath::Namepath, ordinal::Ordinal,
loader::Loader, name::Name, namepath::Namepath, ordinal::Ordinal, output::output, output::output, output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind,
output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind, parser::Parser, parser::Parser, platform::Platform, platform_interface::PlatformInterface, position::Position,
platform::Platform, platform_interface::PlatformInterface, position::Position,
positional::Positional, ran::Ran, range_ext::RangeExt, recipe::Recipe, positional::Positional, ran::Ran, range_ext::RangeExt, recipe::Recipe,
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, scope::Scope, search::Search, recipe_context::RecipeContext, recipe_resolver::RecipeResolver, scope::Scope, search::Search,
search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting, search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting,
@ -139,7 +138,6 @@ mod evaluator;
mod expression; mod expression;
mod fragment; mod fragment;
mod function; mod function;
mod function_context;
mod interrupt_guard; mod interrupt_guard;
mod interrupt_handler; mod interrupt_handler;
mod item; mod item;

View File

@ -6,36 +6,36 @@ pub(crate) enum Thunk<'src> {
Nullary { Nullary {
name: Name<'src>, name: Name<'src>,
#[derivative(Debug = "ignore", PartialEq = "ignore")] #[derivative(Debug = "ignore", PartialEq = "ignore")]
function: fn(&FunctionContext) -> Result<String, String>, function: fn(&Evaluator) -> Result<String, String>,
}, },
Unary { Unary {
name: Name<'src>, name: Name<'src>,
#[derivative(Debug = "ignore", PartialEq = "ignore")] #[derivative(Debug = "ignore", PartialEq = "ignore")]
function: fn(&FunctionContext, &str) -> Result<String, String>, function: fn(&Evaluator, &str) -> Result<String, String>,
arg: Box<Expression<'src>>, arg: Box<Expression<'src>>,
}, },
UnaryOpt { UnaryOpt {
name: Name<'src>, name: Name<'src>,
#[derivative(Debug = "ignore", PartialEq = "ignore")] #[derivative(Debug = "ignore", PartialEq = "ignore")]
function: fn(&FunctionContext, &str, Option<&str>) -> Result<String, String>, function: fn(&Evaluator, &str, Option<&str>) -> Result<String, String>,
args: (Box<Expression<'src>>, Box<Option<Expression<'src>>>), args: (Box<Expression<'src>>, Box<Option<Expression<'src>>>),
}, },
Binary { Binary {
name: Name<'src>, name: Name<'src>,
#[derivative(Debug = "ignore", PartialEq = "ignore")] #[derivative(Debug = "ignore", PartialEq = "ignore")]
function: fn(&FunctionContext, &str, &str) -> Result<String, String>, function: fn(&Evaluator, &str, &str) -> Result<String, String>,
args: [Box<Expression<'src>>; 2], args: [Box<Expression<'src>>; 2],
}, },
BinaryPlus { BinaryPlus {
name: Name<'src>, name: Name<'src>,
#[derivative(Debug = "ignore", PartialEq = "ignore")] #[derivative(Debug = "ignore", PartialEq = "ignore")]
function: fn(&FunctionContext, &str, &str, &[String]) -> Result<String, String>, function: fn(&Evaluator, &str, &str, &[String]) -> Result<String, String>,
args: ([Box<Expression<'src>>; 2], Vec<Expression<'src>>), args: ([Box<Expression<'src>>; 2], Vec<Expression<'src>>),
}, },
Ternary { Ternary {
name: Name<'src>, name: Name<'src>,
#[derivative(Debug = "ignore", PartialEq = "ignore")] #[derivative(Debug = "ignore", PartialEq = "ignore")]
function: fn(&FunctionContext, &str, &str, &str) -> Result<String, String>, function: fn(&Evaluator, &str, &str, &str) -> Result<String, String>,
args: [Box<Expression<'src>>; 3], args: [Box<Expression<'src>>; 3],
}, },
} }