This commit is contained in:
adamnemecek 2024-05-14 20:07:41 -07:00 committed by GitHub
parent c796a253af
commit b85540007e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 171 additions and 181 deletions

View File

@ -14,7 +14,7 @@ impl<'src> Analyzer<'src> {
asts: &HashMap<PathBuf, Ast<'src>>, asts: &HashMap<PathBuf, Ast<'src>>,
root: &Path, root: &Path,
) -> CompileResult<'src, Justfile<'src>> { ) -> CompileResult<'src, Justfile<'src>> {
Analyzer::default().justfile(loaded, paths, asts, root) Self::default().justfile(loaded, paths, asts, root)
} }
fn justfile( fn justfile(

View File

@ -34,21 +34,21 @@ impl Color {
pub(crate) fn auto() -> Self { pub(crate) fn auto() -> Self {
Self { Self {
use_color: UseColor::Auto, use_color: UseColor::Auto,
..Color::default() ..Self::default()
} }
} }
pub(crate) fn always() -> Self { pub(crate) fn always() -> Self {
Self { Self {
use_color: UseColor::Always, use_color: UseColor::Always,
..Color::default() ..Self::default()
} }
} }
pub(crate) fn never() -> Self { pub(crate) fn never() -> Self {
Self { Self {
use_color: UseColor::Never, use_color: UseColor::Never,
..Color::default() ..Self::default()
} }
} }

View File

@ -14,7 +14,7 @@ impl<'src> CompileError<'src> {
pub(crate) fn new(token: Token<'src>, kind: CompileErrorKind<'src>) -> CompileError<'src> { pub(crate) fn new(token: Token<'src>, kind: CompileErrorKind<'src>) -> CompileError<'src> {
Self { Self {
token, token,
kind: Box::new(kind), kind: kind.into(),
} }
} }
} }

View File

@ -8,9 +8,9 @@ impl Compiler {
loader: &'src Loader, loader: &'src Loader,
root: &Path, root: &Path,
) -> RunResult<'src, Compilation<'src>> { ) -> RunResult<'src, Compilation<'src>> {
let mut asts: HashMap<PathBuf, Ast> = HashMap::new(); let mut asts = HashMap::<PathBuf, Ast>::new();
let mut paths: HashMap<PathBuf, PathBuf> = HashMap::new(); let mut paths = HashMap::<PathBuf, PathBuf>::new();
let mut srcs: HashMap<PathBuf, &str> = HashMap::new(); let mut srcs = HashMap::<PathBuf, &str>::new();
let mut loaded = Vec::new(); let mut loaded = Vec::new();
let mut stack = Vec::new(); let mut stack = Vec::new();

View File

@ -1290,7 +1290,7 @@ mod tests {
test! { test! {
name: shell_args_clear, name: shell_args_clear,
args: ["--clear-shell-args"], args: ["--clear-shell-args"],
shell_args: Some(vec![]), shell_args: Some(Vec::new()),
} }
@ -1304,14 +1304,14 @@ mod tests {
test! { test! {
name: shell_args_set_and_clear, name: shell_args_set_and_clear,
args: ["--shell-arg", "bar", "--clear-shell-args"], args: ["--shell-arg", "bar", "--clear-shell-args"],
shell_args: Some(vec![]), shell_args: Some(Vec::new()),
} }
test! { test! {
name: shell_args_set_multiple_and_clear, name: shell_args_set_multiple_and_clear,
args: ["--shell-arg", "bar", "--shell-arg", "baz", "--clear-shell-args"], args: ["--shell-arg", "bar", "--shell-arg", "baz", "--clear-shell-args"],
shell_args: Some(vec![]), shell_args: Some(Vec::new()),
} }

View File

@ -53,23 +53,23 @@ impl<'src> Expression<'src> {
impl<'src> Display for Expression<'src> { impl<'src> Display for Expression<'src> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
match self { match self {
Expression::Assert { condition, error } => write!(f, "assert({condition}, {error})"), Self::Assert { condition, error } => write!(f, "assert({condition}, {error})"),
Expression::Backtick { token, .. } => write!(f, "{}", token.lexeme()), Self::Backtick { token, .. } => write!(f, "{}", token.lexeme()),
Expression::Join { lhs: None, rhs } => write!(f, "/ {rhs}"), Self::Join { lhs: None, rhs } => write!(f, "/ {rhs}"),
Expression::Join { Self::Join {
lhs: Some(lhs), lhs: Some(lhs),
rhs, rhs,
} => write!(f, "{lhs} / {rhs}"), } => write!(f, "{lhs} / {rhs}"),
Expression::Concatenation { lhs, rhs } => write!(f, "{lhs} + {rhs}"), Self::Concatenation { lhs, rhs } => write!(f, "{lhs} + {rhs}"),
Expression::Conditional { Self::Conditional {
condition, condition,
then, then,
otherwise, otherwise,
} => write!(f, "if {condition} {{ {then} }} else {{ {otherwise} }}"), } => write!(f, "if {condition} {{ {then} }} else {{ {otherwise} }}"),
Expression::StringLiteral { string_literal } => write!(f, "{string_literal}"), Self::StringLiteral { string_literal } => write!(f, "{string_literal}"),
Expression::Variable { name } => write!(f, "{}", name.lexeme()), Self::Variable { name } => write!(f, "{}", name.lexeme()),
Expression::Call { thunk } => write!(f, "{thunk}"), Self::Call { thunk } => write!(f, "{thunk}"),
Expression::Group { contents } => write!(f, "({contents})"), Self::Group { contents } => write!(f, "({contents})"),
} }
} }
} }

View File

@ -25,10 +25,10 @@ pub(crate) enum Item<'src> {
impl<'src> Display for Item<'src> { impl<'src> Display for Item<'src> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Item::Alias(alias) => write!(f, "{alias}"), Self::Alias(alias) => write!(f, "{alias}"),
Item::Assignment(assignment) => write!(f, "{assignment}"), Self::Assignment(assignment) => write!(f, "{assignment}"),
Item::Comment(comment) => write!(f, "{comment}"), Self::Comment(comment) => write!(f, "{comment}"),
Item::Import { Self::Import {
relative, optional, .. relative, optional, ..
} => { } => {
write!(f, "import")?; write!(f, "import")?;
@ -39,7 +39,7 @@ impl<'src> Display for Item<'src> {
write!(f, " {relative}") write!(f, " {relative}")
} }
Item::Module { Self::Module {
name, name,
relative, relative,
optional, optional,
@ -59,8 +59,8 @@ impl<'src> Display for Item<'src> {
Ok(()) Ok(())
} }
Item::Recipe(recipe) => write!(f, "{}", recipe.color_display(Color::never())), Self::Recipe(recipe) => write!(f, "{}", recipe.color_display(Color::never())),
Item::Set(set) => write!(f, "{set}"), Self::Set(set) => write!(f, "{set}"),
} }
} }
} }

View File

@ -38,16 +38,16 @@ pub(crate) struct Lexer<'src> {
impl<'src> Lexer<'src> { impl<'src> Lexer<'src> {
/// Lex `src` /// Lex `src`
pub(crate) fn lex(path: &'src Path, src: &'src str) -> CompileResult<'src, Vec<Token<'src>>> { pub(crate) fn lex(path: &'src Path, src: &'src str) -> CompileResult<'src, Vec<Token<'src>>> {
Lexer::new(path, src).tokenize() Self::new(path, src).tokenize()
} }
#[cfg(test)] #[cfg(test)]
pub(crate) fn test_lex(src: &'src str) -> CompileResult<'src, Vec<Token<'src>>> { pub(crate) fn test_lex(src: &'src str) -> CompileResult<'src, Vec<Token<'src>>> {
Lexer::new("justfile".as_ref(), src).tokenize() Self::new("justfile".as_ref(), src).tokenize()
} }
/// Create a new Lexer to lex `src` /// Create a new Lexer to lex `src`
fn new(path: &'src Path, src: &'src str) -> Lexer<'src> { fn new(path: &'src Path, src: &'src str) -> Self {
let mut chars = src.chars(); let mut chars = src.chars();
let next = chars.next(); let next = chars.next();
@ -57,7 +57,7 @@ impl<'src> Lexer<'src> {
line: 0, line: 0,
}; };
Lexer { Self {
indentation: vec![""], indentation: vec![""],
tokens: Vec::new(), tokens: Vec::new(),
token_start: start, token_start: start,
@ -282,11 +282,7 @@ impl<'src> Lexer<'src> {
/// True if `c` can be a continuation character of an identifier /// True if `c` can be a continuation character of an identifier
fn is_identifier_continue(c: char) -> bool { fn is_identifier_continue(c: char) -> bool {
if Self::is_identifier_start(c) { Self::is_identifier_start(c) || matches!(c, '0'..='9' | '-')
return true;
}
matches!(c, '0'..='9' | '-')
} }
/// Consume the text and produce a series of tokens /// Consume the text and produce a series of tokens
@ -1028,7 +1024,7 @@ mod tests {
length, length,
path: "justfile".as_ref(), path: "justfile".as_ref(),
}, },
kind: Box::new(kind), kind: kind.into(),
}; };
assert_eq!(have, want); assert_eq!(have, want);
} }

View File

@ -6,15 +6,15 @@ pub struct List<T: Display, I: Iterator<Item = T> + Clone> {
} }
impl<T: Display, I: Iterator<Item = T> + Clone> List<T, I> { impl<T: Display, I: Iterator<Item = T> + Clone> List<T, I> {
pub fn or<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> { pub fn or<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> Self {
List { Self {
conjunction: "or", conjunction: "or",
values: values.into_iter(), values: values.into_iter(),
} }
} }
pub fn and<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> { pub fn and<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> Self {
List { Self {
conjunction: "and", conjunction: "and",
values: values.into_iter(), values: values.into_iter(),
} }

View File

@ -7,7 +7,7 @@ pub(crate) struct Loader {
impl Loader { impl Loader {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Loader { Self {
srcs: Arena::new(), srcs: Arena::new(),
paths: Arena::new(), paths: Arena::new(),
} }

View File

@ -18,10 +18,10 @@ impl<'src> Node<'src> for Ast<'src> {
impl<'src> Node<'src> for Item<'src> { impl<'src> Node<'src> for Item<'src> {
fn tree(&self) -> Tree<'src> { fn tree(&self) -> Tree<'src> {
match self { match self {
Item::Alias(alias) => alias.tree(), Self::Alias(alias) => alias.tree(),
Item::Assignment(assignment) => assignment.tree(), Self::Assignment(assignment) => assignment.tree(),
Item::Comment(comment) => comment.tree(), Self::Comment(comment) => comment.tree(),
Item::Import { Self::Import {
relative, optional, .. relative, optional, ..
} => { } => {
let mut tree = Tree::atom("import"); let mut tree = Tree::atom("import");
@ -32,7 +32,7 @@ impl<'src> Node<'src> for Item<'src> {
tree.push(format!("{relative}")) tree.push(format!("{relative}"))
} }
Item::Module { Self::Module {
name, name,
optional, optional,
relative, relative,
@ -52,8 +52,8 @@ impl<'src> Node<'src> for Item<'src> {
tree tree
} }
Item::Recipe(recipe) => recipe.tree(), Self::Recipe(recipe) => recipe.tree(),
Item::Set(set) => set.tree(), Self::Set(set) => set.tree(),
} }
} }
} }
@ -83,7 +83,7 @@ impl<'src> Node<'src> for Assignment<'src> {
impl<'src> Node<'src> for Expression<'src> { impl<'src> Node<'src> for Expression<'src> {
fn tree(&self) -> Tree<'src> { fn tree(&self) -> Tree<'src> {
match self { match self {
Expression::Assert { Self::Assert {
condition: Condition { lhs, rhs, operator }, condition: Condition { lhs, rhs, operator },
error, error,
} => Tree::atom(Keyword::Assert.lexeme()) } => Tree::atom(Keyword::Assert.lexeme())
@ -91,8 +91,8 @@ impl<'src> Node<'src> for Expression<'src> {
.push(operator.to_string()) .push(operator.to_string())
.push(rhs.tree()) .push(rhs.tree())
.push(error.tree()), .push(error.tree()),
Expression::Concatenation { lhs, rhs } => Tree::atom("+").push(lhs.tree()).push(rhs.tree()), Self::Concatenation { lhs, rhs } => Tree::atom("+").push(lhs.tree()).push(rhs.tree()),
Expression::Conditional { Self::Conditional {
condition: Condition { lhs, rhs, operator }, condition: Condition { lhs, rhs, operator },
then, then,
otherwise, otherwise,
@ -105,7 +105,7 @@ impl<'src> Node<'src> for Expression<'src> {
tree.push_mut(otherwise.tree()); tree.push_mut(otherwise.tree());
tree tree
} }
Expression::Call { thunk } => { Self::Call { thunk } => {
use Thunk::*; use Thunk::*;
let mut tree = Tree::atom("call"); let mut tree = Tree::atom("call");
@ -158,14 +158,14 @@ impl<'src> Node<'src> for Expression<'src> {
tree tree
} }
Expression::Variable { name } => Tree::atom(name.lexeme()), Self::Variable { name } => Tree::atom(name.lexeme()),
Expression::StringLiteral { Self::StringLiteral {
string_literal: StringLiteral { cooked, .. }, string_literal: StringLiteral { cooked, .. },
} => Tree::string(cooked), } => Tree::string(cooked),
Expression::Backtick { contents, .. } => Tree::atom("backtick").push(Tree::string(contents)), Self::Backtick { contents, .. } => Tree::atom("backtick").push(Tree::string(contents)),
Expression::Group { contents } => Tree::List(vec![contents.tree()]), Self::Group { contents } => Tree::List(vec![contents.tree()]),
Expression::Join { lhs: None, rhs } => Tree::atom("/").push(rhs.tree()), Self::Join { lhs: None, rhs } => Tree::atom("/").push(rhs.tree()),
Expression::Join { Self::Join {
lhs: Some(lhs), lhs: Some(lhs),
rhs, rhs,
} => Tree::atom("/").push(lhs.tree()).push(rhs.tree()), } => Tree::atom("/").push(lhs.tree()).push(rhs.tree()),
@ -258,8 +258,8 @@ impl<'src> Node<'src> for Line<'src> {
impl<'src> Node<'src> for Fragment<'src> { impl<'src> Node<'src> for Fragment<'src> {
fn tree(&self) -> Tree<'src> { fn tree(&self) -> Tree<'src> {
match self { match self {
Fragment::Text { token } => Tree::string(token.lexeme()), Self::Text { token } => Tree::string(token.lexeme()),
Fragment::Interpolation { expression } => Tree::List(vec![expression.tree()]), Self::Interpolation { expression } => Tree::List(vec![expression.tree()]),
} }
} }
} }

View File

@ -479,18 +479,18 @@ impl<'run, 'src> Parser<'run, 'src> {
self.parse_conditional()? self.parse_conditional()?
} else if self.accepted(Slash)? { } else if self.accepted(Slash)? {
let lhs = None; let lhs = None;
let rhs = Box::new(self.parse_expression()?); let rhs = self.parse_expression()?.into();
Expression::Join { lhs, rhs } Expression::Join { lhs, rhs }
} else { } else {
let value = self.parse_value()?; let value = self.parse_value()?;
if self.accepted(Slash)? { if self.accepted(Slash)? {
let lhs = Some(Box::new(value)); let lhs = Some(Box::new(value));
let rhs = Box::new(self.parse_expression()?); let rhs = self.parse_expression()?.into();
Expression::Join { lhs, rhs } Expression::Join { lhs, rhs }
} else if self.accepted(Plus)? { } else if self.accepted(Plus)? {
let lhs = Box::new(value); let lhs = value.into();
let rhs = Box::new(self.parse_expression()?); let rhs = self.parse_expression()?.into();
Expression::Concatenation { lhs, rhs } Expression::Concatenation { lhs, rhs }
} else { } else {
value value
@ -525,8 +525,8 @@ impl<'run, 'src> Parser<'run, 'src> {
Ok(Expression::Conditional { Ok(Expression::Conditional {
condition, condition,
then: Box::new(then), then: then.into(),
otherwise: Box::new(otherwise), otherwise: otherwise.into(),
}) })
} }
@ -542,8 +542,8 @@ impl<'run, 'src> Parser<'run, 'src> {
}; };
let rhs = self.parse_expression()?; let rhs = self.parse_expression()?;
Ok(Condition { Ok(Condition {
lhs: Box::new(lhs), lhs: lhs.into(),
rhs: Box::new(rhs), rhs: rhs.into(),
operator, operator,
}) })
} }
@ -592,7 +592,7 @@ impl<'run, 'src> Parser<'run, 'src> {
} }
} else if self.next_is(ParenL) { } else if self.next_is(ParenL) {
self.presume(ParenL)?; self.presume(ParenL)?;
let contents = Box::new(self.parse_expression()?); let contents = self.parse_expression()?.into();
self.expect(ParenR)?; self.expect(ParenR)?;
Ok(Expression::Group { contents }) Ok(Expression::Group { contents })
} else { } else {
@ -1055,7 +1055,7 @@ mod tests {
length, length,
path: "justfile".as_ref(), path: "justfile".as_ref(),
}, },
kind: Box::new(kind), kind: kind.into(),
}; };
assert_eq!(have, want); assert_eq!(have, want);
} }

View File

@ -1,7 +1,4 @@
use { use super::*;
super::*,
std::process::{ExitStatus, Stdio},
};
/// Return a `Error::Signal` if the process was terminated by a signal, /// Return a `Error::Signal` if the process was terminated by a signal,
/// otherwise return an `Error::UnknownFailure` /// otherwise return an `Error::UnknownFailure`
@ -303,7 +300,7 @@ impl<'src, D> Recipe<'src, D> {
config: &Config, config: &Config,
mut evaluator: Evaluator<'src, 'run>, mut evaluator: Evaluator<'src, 'run>,
) -> RunResult<'src, ()> { ) -> RunResult<'src, ()> {
let mut evaluated_lines = vec![]; let mut evaluated_lines = Vec::new();
for line in &self.body { for line in &self.body {
evaluated_lines.push(evaluator.evaluate_line(line, false)?); evaluated_lines.push(evaluator.evaluate_line(line, false)?);
} }

View File

@ -2,19 +2,19 @@ use super::*;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Scope<'src: 'run, 'run> { pub(crate) struct Scope<'src: 'run, 'run> {
parent: Option<&'run Scope<'src, 'run>>, parent: Option<&'run Self>,
bindings: Table<'src, Binding<'src, String>>, bindings: Table<'src, Binding<'src, String>>,
} }
impl<'src, 'run> Scope<'src, 'run> { impl<'src, 'run> Scope<'src, 'run> {
pub(crate) fn child(&'run self) -> Scope<'src, 'run> { pub(crate) fn child(&'run self) -> Self {
Self { Self {
parent: Some(self), parent: Some(self),
bindings: Table::new(), bindings: Table::new(),
} }
} }
pub(crate) fn new() -> Scope<'src, 'run> { pub(crate) fn new() -> Self {
Self { Self {
parent: None, parent: None,
bindings: Table::new(), bindings: Table::new(),
@ -50,7 +50,7 @@ impl<'src, 'run> Scope<'src, 'run> {
self.bindings.keys().copied() self.bindings.keys().copied()
} }
pub(crate) fn parent(&self) -> Option<&'run Scope<'src, 'run>> { pub(crate) fn parent(&self) -> Option<&'run Self> {
self.parent self.parent
} }
} }

View File

@ -21,17 +21,17 @@ pub(crate) enum Setting<'src> {
impl<'src> Display for Setting<'src> { impl<'src> Display for Setting<'src> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
match self { match self {
Setting::AllowDuplicateRecipes(value) Self::AllowDuplicateRecipes(value)
| Setting::AllowDuplicateVariables(value) | Self::AllowDuplicateVariables(value)
| Setting::DotenvLoad(value) | Self::DotenvLoad(value)
| Setting::Export(value) | Self::Export(value)
| Setting::Fallback(value) | Self::Fallback(value)
| Setting::IgnoreComments(value) | Self::IgnoreComments(value)
| Setting::PositionalArguments(value) | Self::PositionalArguments(value)
| Setting::Quiet(value) | Self::Quiet(value)
| Setting::WindowsPowerShell(value) => write!(f, "{value}"), | Self::WindowsPowerShell(value) => write!(f, "{value}"),
Setting::Shell(shell) | Setting::WindowsShell(shell) => write!(f, "{shell}"), Self::Shell(shell) | Self::WindowsShell(shell) => write!(f, "{shell}"),
Setting::DotenvFilename(value) | Setting::DotenvPath(value) | Setting::Tempdir(value) => { Self::DotenvFilename(value) | Self::DotenvPath(value) | Self::Tempdir(value) => {
write!(f, "{value:?}") write!(f, "{value:?}")
} }
} }

View File

@ -5,7 +5,7 @@ pub(crate) struct Shebang<'line> {
} }
impl<'line> Shebang<'line> { impl<'line> Shebang<'line> {
pub(crate) fn new(line: &'line str) -> Option<Shebang<'line>> { pub(crate) fn new(line: &'line str) -> Option<Self> {
if !line.starts_with("#!") { if !line.starts_with("#!") {
return None; return None;
} }
@ -24,7 +24,7 @@ impl<'line> Shebang<'line> {
return None; return None;
} }
Some(Shebang { Some(Self {
interpreter, interpreter,
argument, argument,
}) })

View File

@ -45,7 +45,7 @@ pub struct Summary {
} }
impl Summary { impl Summary {
fn new(justfile: &full::Justfile) -> Summary { fn new(justfile: &full::Justfile) -> Self {
let mut aliases = BTreeMap::new(); let mut aliases = BTreeMap::new();
for alias in justfile.aliases.values() { for alias in justfile.aliases.values() {
@ -55,7 +55,7 @@ impl Summary {
.push(alias.name.to_string()); .push(alias.name.to_string());
} }
Summary { Self {
recipes: justfile recipes: justfile
.recipes .recipes
.iter() .iter()
@ -87,8 +87,8 @@ pub struct Recipe {
} }
impl Recipe { impl Recipe {
fn new(recipe: &full::Recipe, aliases: Vec<String>) -> Recipe { fn new(recipe: &full::Recipe, aliases: Vec<String>) -> Self {
Recipe { Self {
private: recipe.private, private: recipe.private,
shebang: recipe.shebang, shebang: recipe.shebang,
quiet: recipe.quiet, quiet: recipe.quiet,
@ -108,8 +108,8 @@ pub struct Parameter {
} }
impl Parameter { impl Parameter {
fn new(parameter: &full::Parameter) -> Parameter { fn new(parameter: &full::Parameter) -> Self {
Parameter { Self {
kind: ParameterKind::new(parameter.kind), kind: ParameterKind::new(parameter.kind),
name: parameter.name.lexeme().to_owned(), name: parameter.name.lexeme().to_owned(),
default: parameter.default.as_ref().map(Expression::new), default: parameter.default.as_ref().map(Expression::new),
@ -140,8 +140,8 @@ pub struct Line {
} }
impl Line { impl Line {
fn new(line: &full::Line) -> Line { fn new(line: &full::Line) -> Self {
Line { Self {
fragments: line.fragments.iter().map(Fragment::new).collect(), fragments: line.fragments.iter().map(Fragment::new).collect(),
} }
} }
@ -154,12 +154,12 @@ pub enum Fragment {
} }
impl Fragment { impl Fragment {
fn new(fragment: &full::Fragment) -> Fragment { fn new(fragment: &full::Fragment) -> Self {
match fragment { match fragment {
full::Fragment::Text { token } => Fragment::Text { full::Fragment::Text { token } => Self::Text {
text: token.lexeme().to_owned(), text: token.lexeme().to_owned(),
}, },
full::Fragment::Interpolation { expression } => Fragment::Expression { full::Fragment::Interpolation { expression } => Self::Expression {
expression: Expression::new(expression), expression: Expression::new(expression),
}, },
} }
@ -173,8 +173,8 @@ pub struct Assignment {
} }
impl Assignment { impl Assignment {
fn new(assignment: &full::Assignment) -> Assignment { fn new(assignment: &full::Assignment) -> Self {
Assignment { Self {
exported: assignment.export, exported: assignment.export,
expression: Expression::new(&assignment.value), expression: Expression::new(&assignment.value),
} }
@ -218,7 +218,7 @@ pub enum Expression {
} }
impl Expression { impl Expression {
fn new(expression: &full::Expression) -> Expression { fn new(expression: &full::Expression) -> Self {
use full::Expression::*; use full::Expression::*;
match expression { match expression {
Assert { Assert {
@ -232,51 +232,51 @@ impl Expression {
}, },
error: Box::new(Expression::new(error)), error: Box::new(Expression::new(error)),
}, },
Backtick { contents, .. } => Expression::Backtick { Backtick { contents, .. } => Self::Backtick {
command: (*contents).clone(), command: (*contents).clone(),
}, },
Call { thunk } => match thunk { Call { thunk } => match thunk {
full::Thunk::Nullary { name, .. } => Expression::Call { full::Thunk::Nullary { name, .. } => Self::Call {
name: name.lexeme().to_owned(), name: name.lexeme().to_owned(),
arguments: Vec::new(), arguments: Vec::new(),
}, },
full::Thunk::Unary { name, arg, .. } => Expression::Call { full::Thunk::Unary { name, arg, .. } => Self::Call {
name: name.lexeme().to_owned(), name: name.lexeme().to_owned(),
arguments: vec![Expression::new(arg)], arguments: vec![Self::new(arg)],
}, },
full::Thunk::UnaryOpt { full::Thunk::UnaryOpt {
name, name,
args: (a, opt_b), args: (a, opt_b),
.. ..
} => { } => {
let mut arguments = vec![]; let mut arguments = Vec::new();
if let Some(b) = opt_b.as_ref() { if let Some(b) = opt_b.as_ref() {
arguments.push(Expression::new(b)); arguments.push(Self::new(b));
} }
arguments.push(Expression::new(a)); arguments.push(Self::new(a));
Expression::Call { Self::Call {
name: name.lexeme().to_owned(), name: name.lexeme().to_owned(),
arguments, arguments,
} }
} }
full::Thunk::Binary { full::Thunk::Binary {
name, args: [a, b], .. name, args: [a, b], ..
} => Expression::Call { } => Self::Call {
name: name.lexeme().to_owned(), name: name.lexeme().to_owned(),
arguments: vec![Expression::new(a), Expression::new(b)], arguments: vec![Self::new(a), Self::new(b)],
}, },
full::Thunk::BinaryPlus { full::Thunk::BinaryPlus {
name, name,
args: ([a, b], rest), args: ([a, b], rest),
.. ..
} => { } => {
let mut arguments = vec![Expression::new(a), Expression::new(b)]; let mut arguments = vec![Self::new(a), Self::new(b)];
for arg in rest { for arg in rest {
arguments.push(Expression::new(arg)); arguments.push(Self::new(arg));
} }
Expression::Call { Self::Call {
name: name.lexeme().to_owned(), name: name.lexeme().to_owned(),
arguments, arguments,
} }
@ -285,37 +285,37 @@ impl Expression {
name, name,
args: [a, b, c], args: [a, b, c],
.. ..
} => Expression::Call { } => Self::Call {
name: name.lexeme().to_owned(), name: name.lexeme().to_owned(),
arguments: vec![Expression::new(a), Expression::new(b), Expression::new(c)], arguments: vec![Self::new(a), Self::new(b), Self::new(c)],
}, },
}, },
Concatenation { lhs, rhs } => Expression::Concatenation { Concatenation { lhs, rhs } => Self::Concatenation {
lhs: Box::new(Expression::new(lhs)), lhs: Self::new(lhs).into(),
rhs: Box::new(Expression::new(rhs)), rhs: Self::new(rhs).into(),
}, },
Join { lhs, rhs } => Expression::Join { Join { lhs, rhs } => Self::Join {
lhs: lhs.as_ref().map(|lhs| Box::new(Expression::new(lhs))), lhs: lhs.as_ref().map(|lhs| Self::new(lhs).into()),
rhs: Box::new(Expression::new(rhs)), rhs: Self::new(rhs).into(),
}, },
Conditional { Conditional {
condition: full::Condition { lhs, rhs, operator }, condition: full::Condition { lhs, rhs, operator },
otherwise, otherwise,
then, then,
} => Expression::Conditional { } => Self::Conditional {
lhs: Box::new(Expression::new(lhs)), lhs: Self::new(lhs).into(),
operator: ConditionalOperator::new(*operator), operator: ConditionalOperator::new(*operator),
otherwise: Box::new(Expression::new(otherwise)), otherwise: Self::new(otherwise).into(),
rhs: Box::new(Expression::new(rhs)), rhs: Self::new(rhs).into(),
then: Box::new(Expression::new(then)), then: Self::new(then).into(),
}, },
StringLiteral { string_literal } => Expression::String { StringLiteral { string_literal } => Self::String {
text: string_literal.cooked.clone(), text: string_literal.cooked.clone(),
}, },
Variable { name, .. } => Expression::Variable { Variable { name, .. } => Self::Variable {
name: name.lexeme().to_owned(), name: name.lexeme().to_owned(),
}, },
Group { contents } => Expression::new(contents), Group { contents } => Self::new(contents),
} }
} }
} }

View File

@ -7,8 +7,8 @@ pub(crate) struct Table<'key, V: Keyed<'key>> {
} }
impl<'key, V: Keyed<'key>> Table<'key, V> { impl<'key, V: Keyed<'key>> Table<'key, V> {
pub(crate) fn new() -> Table<'key, V> { pub(crate) fn new() -> Self {
Table { Self {
map: BTreeMap::new(), map: BTreeMap::new(),
} }
} }
@ -63,7 +63,7 @@ impl<'key, V: Keyed<'key>> Default for Table<'key, V> {
impl<'key, V: Keyed<'key>> FromIterator<V> for Table<'key, V> { impl<'key, V: Keyed<'key>> FromIterator<V> for Table<'key, V> {
fn from_iter<I: IntoIterator<Item = V>>(iter: I) -> Self { fn from_iter<I: IntoIterator<Item = V>>(iter: I) -> Self {
Table { Self {
map: iter.into_iter().map(|value| (value.key(), value)).collect(), map: iter.into_iter().map(|value| (value.key(), value)).collect(),
} }
} }

View File

@ -88,7 +88,7 @@ pub(crate) fn analysis_error(
length, length,
path: "justfile".as_ref(), path: "justfile".as_ref(),
}, },
kind: Box::new(kind), kind: kind.into(),
}; };
assert_eq!(have, want); assert_eq!(have, want);
} }

View File

@ -64,14 +64,14 @@ impl<'src> Thunk<'src> {
(Function::Nullary(function), 0) => Ok(Thunk::Nullary { function, name }), (Function::Nullary(function), 0) => Ok(Thunk::Nullary { function, name }),
(Function::Unary(function), 1) => Ok(Thunk::Unary { (Function::Unary(function), 1) => Ok(Thunk::Unary {
function, function,
arg: Box::new(arguments.pop().unwrap()), arg: arguments.pop().unwrap().into(),
name, name,
}), }),
(Function::UnaryOpt(function), 1..=2) => { (Function::UnaryOpt(function), 1..=2) => {
let a = Box::new(arguments.remove(0)); let a = arguments.remove(0).into();
let b = match arguments.pop() { let b = match arguments.pop() {
Some(value) => Box::new(Some(value)), Some(value) => Some(value).into(),
None => Box::new(None), None => None.into(),
}; };
Ok(Thunk::UnaryOpt { Ok(Thunk::UnaryOpt {
function, function,
@ -80,8 +80,8 @@ impl<'src> Thunk<'src> {
}) })
} }
(Function::Binary(function), 2) => { (Function::Binary(function), 2) => {
let b = Box::new(arguments.pop().unwrap()); let b = arguments.pop().unwrap().into();
let a = Box::new(arguments.pop().unwrap()); let a = arguments.pop().unwrap().into();
Ok(Thunk::Binary { Ok(Thunk::Binary {
function, function,
args: [a, b], args: [a, b],
@ -90,8 +90,8 @@ impl<'src> Thunk<'src> {
} }
(Function::BinaryPlus(function), 2..=usize::MAX) => { (Function::BinaryPlus(function), 2..=usize::MAX) => {
let rest = arguments.drain(2..).collect(); let rest = arguments.drain(2..).collect();
let b = Box::new(arguments.pop().unwrap()); let b = arguments.pop().unwrap().into();
let a = Box::new(arguments.pop().unwrap()); let a = arguments.pop().unwrap().into();
Ok(Thunk::BinaryPlus { Ok(Thunk::BinaryPlus {
function, function,
args: ([a, b], rest), args: ([a, b], rest),
@ -99,9 +99,9 @@ impl<'src> Thunk<'src> {
}) })
} }
(Function::Ternary(function), 3) => { (Function::Ternary(function), 3) => {
let c = Box::new(arguments.pop().unwrap()); let c = arguments.pop().unwrap().into();
let b = Box::new(arguments.pop().unwrap()); let b = arguments.pop().unwrap().into();
let a = Box::new(arguments.pop().unwrap()); let a = arguments.pop().unwrap().into();
Ok(Thunk::Ternary { Ok(Thunk::Ternary {
function, function,
args: [a, b, c], args: [a, b, c],

View File

@ -1,7 +1,4 @@
use { use {super::*, std::borrow::Cow};
super::*,
std::{borrow::Cow, mem},
};
/// Construct a `Tree` from a symbolic expression literal. This macro, and the /// Construct a `Tree` from a symbolic expression literal. This macro, and the
/// Tree type, are only used in the Parser unit tests, providing a concise /// Tree type, are only used in the Parser unit tests, providing a concise
@ -54,66 +51,66 @@ pub(crate) enum Tree<'text> {
/// …an atom containing text, or… /// …an atom containing text, or…
Atom(Cow<'text, str>), Atom(Cow<'text, str>),
/// …a list containing zero or more `Tree`s. /// …a list containing zero or more `Tree`s.
List(Vec<Tree<'text>>), List(Vec<Self>),
} }
impl<'text> Tree<'text> { impl<'text> Tree<'text> {
/// Construct an Atom from a text scalar /// Construct an Atom from a text scalar
pub(crate) fn atom(text: impl Into<Cow<'text, str>>) -> Tree<'text> { pub(crate) fn atom(text: impl Into<Cow<'text, str>>) -> Self {
Tree::Atom(text.into()) Self::Atom(text.into())
} }
/// Construct a List from an iterable of trees /// Construct a List from an iterable of trees
pub(crate) fn list(children: impl IntoIterator<Item = Tree<'text>>) -> Tree<'text> { pub(crate) fn list(children: impl IntoIterator<Item = Self>) -> Self {
Tree::List(children.into_iter().collect()) Self::List(children.into_iter().collect())
} }
/// Convenience function to create an atom containing quoted text /// Convenience function to create an atom containing quoted text
pub(crate) fn string(contents: impl AsRef<str>) -> Tree<'text> { pub(crate) fn string(contents: impl AsRef<str>) -> Self {
Tree::atom(format!("\"{}\"", contents.as_ref())) Self::atom(format!("\"{}\"", contents.as_ref()))
} }
/// Push a child node into self, turning it into a List if it was an Atom /// Push a child node into self, turning it into a List if it was an Atom
pub(crate) fn push(self, tree: impl Into<Tree<'text>>) -> Tree<'text> { pub(crate) fn push(self, tree: impl Into<Self>) -> Self {
match self { match self {
Tree::List(mut children) => { Self::List(mut children) => {
children.push(tree.into()); children.push(tree.into());
Tree::List(children) Self::List(children)
} }
Tree::Atom(text) => Tree::List(vec![Tree::Atom(text), tree.into()]), Self::Atom(text) => Self::List(vec![Self::Atom(text), tree.into()]),
} }
} }
/// Extend a self with a tail of Trees, turning self into a List if it was an /// Extend a self with a tail of Trees, turning self into a List if it was an
/// Atom /// Atom
pub(crate) fn extend<I, T>(self, tail: I) -> Tree<'text> pub(crate) fn extend<I, T>(self, tail: I) -> Self
where where
I: IntoIterator<Item = T>, I: IntoIterator<Item = T>,
T: Into<Tree<'text>>, T: Into<Self>,
{ {
// Tree::List(children.into_iter().collect()) // Tree::List(children.into_iter().collect())
let mut head = match self { let mut head = match self {
Tree::List(children) => children, Self::List(children) => children,
Tree::Atom(text) => vec![Tree::Atom(text)], Self::Atom(text) => vec![Self::Atom(text)],
}; };
for child in tail { for child in tail {
head.push(child.into()); head.push(child.into());
} }
Tree::List(head) Self::List(head)
} }
/// Like `push`, but modify self in-place /// Like `push`, but modify self in-place
pub(crate) fn push_mut(&mut self, tree: impl Into<Tree<'text>>) { pub(crate) fn push_mut(&mut self, tree: impl Into<Self>) {
*self = mem::replace(self, Tree::List(Vec::new())).push(tree.into()); *self = mem::replace(self, Self::List(Vec::new())).push(tree.into());
} }
} }
impl Display for Tree<'_> { impl Display for Tree<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Tree::List(children) => { Self::List(children) => {
write!(f, "(")?; write!(f, "(")?;
for (i, child) in children.iter().enumerate() { for (i, child) in children.iter().enumerate() {
@ -125,7 +122,7 @@ impl Display for Tree<'_> {
write!(f, ")") write!(f, ")")
} }
Tree::Atom(text) => write!(f, "{text}"), Self::Atom(text) => write!(f, "{text}"),
} }
} }
} }
@ -134,7 +131,7 @@ impl<'text, T> From<T> for Tree<'text>
where where
T: Into<Cow<'text, str>>, T: Into<Cow<'text, str>>,
{ {
fn from(text: T) -> Tree<'text> { fn from(text: T) -> Self {
Tree::Atom(text.into()) Self::Atom(text.into())
} }
} }

View File

@ -5,8 +5,8 @@ pub(crate) struct Variables<'expression, 'src> {
} }
impl<'expression, 'src> Variables<'expression, 'src> { impl<'expression, 'src> Variables<'expression, 'src> {
pub(crate) fn new(root: &'expression Expression<'src>) -> Variables<'expression, 'src> { pub(crate) fn new(root: &'expression Expression<'src>) -> Self {
Variables { stack: vec![root] } Self { stack: vec![root] }
} }
} }

View File

@ -2,7 +2,7 @@ use super::*;
#[test] #[test]
fn readme() { fn readme() {
let mut justfiles = vec![]; let mut justfiles = Vec::new();
let mut current = None; let mut current = None;
for line in fs::read_to_string("README.md").unwrap().lines() { for line in fs::read_to_string("README.md").unwrap().lines() {