Cleanup (#2026)
This commit is contained in:
parent
c796a253af
commit
b85540007e
@ -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(
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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()),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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})"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
src/item.rs
14
src/item.rs
@ -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}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/lexer.rs
16
src/lexer.rs
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
|
38
src/node.rs
38
src/node.rs
@ -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()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)?);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
22
src/thunk.rs
22
src/thunk.rs
@ -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],
|
||||||
|
49
src/tree.rs
49
src/tree.rs
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user