It expansion (#1668)

* First step in it-expansion

* Fix tests

* fix clippy warnings
This commit is contained in:
Jonathan Turner
2020-04-27 14:04:54 +12:00
committed by GitHub
parent 6f2ef05195
commit 8bd3cedce1
37 changed files with 1040 additions and 1002 deletions

View File

@ -77,6 +77,36 @@ pub enum ClassifiedCommand {
Error(ParseError),
}
impl ClassifiedCommand {
pub fn has_it_iteration(&self) -> bool {
match self {
ClassifiedCommand::Internal(command) => {
if let SpannedExpression {
expr: Expression::Literal(Literal::String(s)),
..
} = &*command.args.head
{
if s == "run_external" {
// For now, don't it-expand externals
return false;
}
}
let mut result = command.args.head.has_shallow_it_usage();
if let Some(positionals) = &command.args.positional {
for arg in positionals {
result = result || arg.has_shallow_it_usage();
}
}
result
}
ClassifiedCommand::Expr(expr) => expr.has_shallow_it_usage(),
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct Commands {
pub list: Vec<ClassifiedCommand>,
@ -91,6 +121,37 @@ impl Commands {
pub fn push(&mut self, command: ClassifiedCommand) {
self.list.push(command);
}
/// Convert all shallow uses of $it to `each { use of $it }`, converting each to a per-row command
pub fn expand_it_usage(&mut self) {
for idx in 0..self.list.len() {
if self.list[idx].has_it_iteration() {
self.list[idx] = ClassifiedCommand::Internal(InternalCommand {
name: "each".to_string(),
name_span: self.span,
args: hir::Call {
head: Box::new(SpannedExpression {
expr: Expression::Synthetic(Synthetic::String("each".to_string())),
span: self.span,
}),
named: None,
span: self.span,
positional: Some(vec![SpannedExpression {
expr: Expression::Block(Block {
block: vec![Commands {
list: vec![self.list[idx].clone()],
span: self.span,
}],
span: self.span,
}),
span: self.span,
}]),
is_last: false, // FIXME
},
})
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
@ -110,6 +171,13 @@ impl Block {
pub fn push(&mut self, commands: Commands) {
self.block.push(commands);
}
/// Convert all shallow uses of $it to `each { use of $it }`, converting each to a per-row command
pub fn expand_it_usage(&mut self) {
for commands in &mut self.block {
commands.expand_it_usage();
}
}
}
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, Deserialize, Serialize)]
@ -201,14 +269,6 @@ pub enum Member {
}
impl Member {
// pub fn int(span: Span, source: &Text) -> Member {
// if let Ok(big_int) = BigInt::from_str(span.slice(source)) {
// Member::Int(big_int, span)
// } else {
// unreachable!("Internal error: could not convert text to BigInt as expected")
// }
// }
pub fn to_path_member(&self) -> PathMember {
match self {
//Member::String(outer, inner) => PathMember::string(inner.slice(source), *outer),
@ -459,6 +519,17 @@ impl SpannedExpression {
_ => 0,
}
}
pub fn has_shallow_it_usage(&self) -> bool {
match &self.expr {
Expression::Binary(binary) => {
binary.left.has_shallow_it_usage() || binary.right.has_shallow_it_usage()
}
Expression::Variable(Variable::It(_)) => true,
Expression::Path(path) => path.head.has_shallow_it_usage(),
_ => false,
}
}
}
impl std::ops::Deref for SpannedExpression {