Replace FunctionContext with Evaluator (#2048)
This commit is contained in:
parent
843286f27c
commit
7359deeb99
@ -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()),
|
||||||
|
160
src/function.rs
160
src/function.rs
@ -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> {
|
||||||
|
@ -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,
|
|
||||||
}
|
|
12
src/lib.rs
12
src/lib.rs
@ -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;
|
||||||
|
12
src/thunk.rs
12
src/thunk.rs
@ -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],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user