refactor(source): name private analysis expression kind explicitly
This commit is contained in:
@@ -33,7 +33,7 @@ pub struct Argument {
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Expression {
|
||||
pub kind: Kind,
|
||||
pub kind: ExpressionKind,
|
||||
pub span: Span,
|
||||
pub depth: usize,
|
||||
pub grouped: bool,
|
||||
@@ -47,7 +47,7 @@ pub struct LiteralSyntax {
|
||||
pub tokens: Vec<Span>,
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Kind {
|
||||
pub enum ExpressionKind {
|
||||
Boolean(bool),
|
||||
Number(Exact),
|
||||
Quantity {
|
||||
|
||||
@@ -64,7 +64,7 @@ pub(super) fn parse(source: &str, tokens: &[Token], budget: &mut Budget) -> Resu
|
||||
let value = p.text() == "true";
|
||||
let span = p.span();
|
||||
p.cursor += 1;
|
||||
values.push(p.node(Kind::Boolean(value), span)?);
|
||||
values.push(p.node(ExpressionKind::Boolean(value), span)?);
|
||||
}
|
||||
"-" => {
|
||||
p.open()?;
|
||||
@@ -95,14 +95,18 @@ pub(super) fn parse(source: &str, tokens: &[Token], budget: &mut Budget) -> Resu
|
||||
)));
|
||||
} else {
|
||||
let end = reference.span.end;
|
||||
values.push(p.node(Kind::Property(reference), Span { start, end })?);
|
||||
values.push(
|
||||
p.node(ExpressionKind::Property(reference), Span { start, end })?,
|
||||
);
|
||||
}
|
||||
}
|
||||
"$" => {
|
||||
p.cursor += 1;
|
||||
let reference = p.reference()?;
|
||||
let end = reference.span.end;
|
||||
values.push(p.node(Kind::Parameter(reference), Span { start, end })?);
|
||||
values.push(
|
||||
p.node(ExpressionKind::Parameter(reference), Span { start, end })?,
|
||||
);
|
||||
}
|
||||
"ratio" => {
|
||||
let (value, literal) = p.ratio()?;
|
||||
@@ -184,7 +188,7 @@ pub(super) fn parse(source: &str, tokens: &[Token], budget: &mut Budget) -> Resu
|
||||
end: right.span.end,
|
||||
};
|
||||
values.push(p.node(
|
||||
Kind::Binary {
|
||||
ExpressionKind::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(right),
|
||||
@@ -197,7 +201,7 @@ pub(super) fn parse(source: &str, tokens: &[Token], budget: &mut Budget) -> Resu
|
||||
let end = operand.span.end;
|
||||
p.close();
|
||||
values.push(p.node(
|
||||
Kind::Unary {
|
||||
ExpressionKind::Unary {
|
||||
op,
|
||||
operand: Box::new(operand),
|
||||
},
|
||||
@@ -292,7 +296,7 @@ pub(super) fn parse(source: &str, tokens: &[Token], budget: &mut Budget) -> Resu
|
||||
let end = p.take(")")?.end;
|
||||
p.close();
|
||||
values.push(p.node(
|
||||
Kind::Power {
|
||||
ExpressionKind::Power {
|
||||
base: Box::new(base),
|
||||
exponent,
|
||||
},
|
||||
@@ -304,7 +308,7 @@ pub(super) fn parse(source: &str, tokens: &[Token], budget: &mut Budget) -> Resu
|
||||
let end = p.take(")")?.end;
|
||||
p.close();
|
||||
values.push(p.node(
|
||||
Kind::AsKind {
|
||||
ExpressionKind::AsKind {
|
||||
kind,
|
||||
value: Box::new(value),
|
||||
},
|
||||
@@ -441,29 +445,32 @@ impl Parser<'_, '_> {
|
||||
let unit = self.reference()?;
|
||||
let end = self.take("]")?.end;
|
||||
self.close();
|
||||
self.node(Kind::Quantity { magnitude, unit }, Span { start, end })
|
||||
self.node(
|
||||
ExpressionKind::Quantity { magnitude, unit },
|
||||
Span { start, end },
|
||||
)
|
||||
} else {
|
||||
self.node(Kind::Number(magnitude), Span { start, end })
|
||||
self.node(ExpressionKind::Number(magnitude), Span { start, end })
|
||||
}?;
|
||||
expression.literal = Some(literal);
|
||||
Ok(expression)
|
||||
}
|
||||
fn node(&mut self, kind: Kind, span: Span) -> Result<Expression, Error> {
|
||||
fn node(&mut self, kind: ExpressionKind, span: Span) -> Result<Expression, Error> {
|
||||
let child_depth = match &kind {
|
||||
Kind::Unary { operand, .. } => operand.depth,
|
||||
Kind::Binary { left, right, .. } => left.depth.max(right.depth),
|
||||
Kind::If {
|
||||
ExpressionKind::Unary { operand, .. } => operand.depth,
|
||||
ExpressionKind::Binary { left, right, .. } => left.depth.max(right.depth),
|
||||
ExpressionKind::If {
|
||||
condition,
|
||||
when_true,
|
||||
when_false,
|
||||
} => condition.depth.max(when_true.depth).max(when_false.depth),
|
||||
Kind::List(values) => values.iter().map(|v| v.depth).max().unwrap_or(0),
|
||||
Kind::Call { arguments, .. } => {
|
||||
ExpressionKind::List(values) => values.iter().map(|v| v.depth).max().unwrap_or(0),
|
||||
ExpressionKind::Call { arguments, .. } => {
|
||||
arguments.iter().map(|a| a.value.depth).max().unwrap_or(0)
|
||||
}
|
||||
Kind::Sum { values, initial } => values.depth.max(initial.depth),
|
||||
Kind::Power { base, .. } => base.depth,
|
||||
Kind::AsKind { value, .. } => value.depth,
|
||||
ExpressionKind::Sum { values, initial } => values.depth.max(initial.depth),
|
||||
ExpressionKind::Power { base, .. } => base.depth,
|
||||
ExpressionKind::AsKind { value, .. } => value.depth,
|
||||
_ => 0,
|
||||
};
|
||||
if child_depth >= crate::analysis::MAX_EXPRESSION_DEPTH {
|
||||
@@ -490,21 +497,21 @@ impl Parser<'_, '_> {
|
||||
.ok_or_else(|| error(span, "Missing required constructor argument."))
|
||||
};
|
||||
let kind = match sequence.kind {
|
||||
SequenceKind::If => Kind::If {
|
||||
SequenceKind::If => ExpressionKind::If {
|
||||
condition: next()?,
|
||||
when_true: next()?,
|
||||
when_false: next()?,
|
||||
},
|
||||
SequenceKind::Sum => Kind::Sum {
|
||||
SequenceKind::Sum => ExpressionKind::Sum {
|
||||
values: next()?,
|
||||
initial: next()?,
|
||||
},
|
||||
SequenceKind::Unary(op) => Kind::Unary {
|
||||
SequenceKind::Unary(op) => ExpressionKind::Unary {
|
||||
op,
|
||||
operand: next()?,
|
||||
},
|
||||
SequenceKind::List => Kind::List(values.map(|(_, value)| value).collect()),
|
||||
SequenceKind::Call(definition) => Kind::Call {
|
||||
SequenceKind::List => ExpressionKind::List(values.map(|(_, value)| value).collect()),
|
||||
SequenceKind::Call(definition) => ExpressionKind::Call {
|
||||
definition,
|
||||
arguments: values
|
||||
.map(|(parameter, value)| Argument {
|
||||
@@ -529,7 +536,7 @@ fn comparison(op: BinaryOp) -> bool {
|
||||
)
|
||||
}
|
||||
fn ungrouped_comparison(value: &Expression) -> bool {
|
||||
!value.grouped && matches!(&value.kind, Kind::Binary { op, .. } if comparison(*op))
|
||||
!value.grouped && matches!(&value.kind, ExpressionKind::Binary { op, .. } if comparison(*op))
|
||||
}
|
||||
fn operator(text: &str) -> Option<(BinaryOp, u8)> {
|
||||
Some(match text {
|
||||
|
||||
@@ -15,14 +15,14 @@ fn expression(source: &str) -> Expression {
|
||||
}
|
||||
}
|
||||
fn number(value: &Expression) -> String {
|
||||
let Kind::Number(exact) = &value.kind else {
|
||||
let ExpressionKind::Number(exact) = &value.kind else {
|
||||
panic!("expected Number");
|
||||
};
|
||||
exact.canonical_literal()
|
||||
}
|
||||
|
||||
fn binary_children(value: Expression, expected: BinaryOp) -> (Expression, Expression) {
|
||||
let Kind::Binary { op, left, right } = value.kind else {
|
||||
let ExpressionKind::Binary { op, left, right } = value.kind else {
|
||||
panic!("expected Binary {expected:?}");
|
||||
};
|
||||
assert_eq!(op, expected);
|
||||
@@ -41,18 +41,18 @@ fn mixed_precedence_and_grouping_have_independent_expected_child_topology() {
|
||||
|
||||
let (conjunction, last) =
|
||||
binary_children(expression("not(false) and true or false"), BinaryOp::Or);
|
||||
assert_eq!(last.kind, Kind::Boolean(false));
|
||||
assert_eq!(last.kind, ExpressionKind::Boolean(false));
|
||||
let (negated, middle) = binary_children(conjunction, BinaryOp::And);
|
||||
assert_eq!(middle.kind, Kind::Boolean(true));
|
||||
let Kind::Unary { op, operand } = negated.kind else {
|
||||
assert_eq!(middle.kind, ExpressionKind::Boolean(true));
|
||||
let ExpressionKind::Unary { op, operand } = negated.kind else {
|
||||
panic!("expected Not");
|
||||
};
|
||||
assert_eq!(op, UnaryOp::Not);
|
||||
assert_eq!(operand.kind, Kind::Boolean(false));
|
||||
assert_eq!(operand.kind, ExpressionKind::Boolean(false));
|
||||
|
||||
let (negative, two) = binary_children(expression("-1 * 2"), BinaryOp::Multiply);
|
||||
assert_eq!(number(&two), "2");
|
||||
let Kind::Unary { op, operand } = negative.kind else {
|
||||
let ExpressionKind::Unary { op, operand } = negative.kind else {
|
||||
panic!("expected Negate");
|
||||
};
|
||||
assert_eq!(op, UnaryOp::Negate);
|
||||
@@ -85,10 +85,10 @@ fn flat_binary_depth_and_malformed_constructor_retain_bounded_completed_children
|
||||
// Independently verify the complete left-associated shape, not just depth.
|
||||
for _ in 1..128 {
|
||||
let (left, right) = binary_children(tree, BinaryOp::And);
|
||||
assert_eq!(right.kind, Kind::Boolean(true));
|
||||
assert_eq!(right.kind, ExpressionKind::Boolean(true));
|
||||
tree = left;
|
||||
}
|
||||
assert_eq!(tree.kind, Kind::Boolean(true));
|
||||
assert_eq!(tree.kind, ExpressionKind::Boolean(true));
|
||||
assert!(
|
||||
parse(&flat(129), &mut budget())
|
||||
.unwrap_err()
|
||||
@@ -129,7 +129,7 @@ fn significant_ratio_and_quantity_trivia_preserve_original_spans() {
|
||||
.collect::<Vec<_>>(),
|
||||
["ratio", "(", "-", "3", ",", "4", ")"]
|
||||
);
|
||||
let Kind::Quantity { magnitude, unit } = parsed.kind else {
|
||||
let ExpressionKind::Quantity { magnitude, unit } = parsed.kind else {
|
||||
panic!("expected Quantity");
|
||||
};
|
||||
assert_eq!(magnitude.canonical_literal(), "ratio(-3, 4)");
|
||||
@@ -192,14 +192,14 @@ fn unary_literals_precedence_and_comparison_children_keep_distinct_trees() {
|
||||
let negative = expression("-(1)");
|
||||
assert!(matches!(
|
||||
negative.kind,
|
||||
Kind::Unary {
|
||||
ExpressionKind::Unary {
|
||||
op: UnaryOp::Negate,
|
||||
..
|
||||
}
|
||||
));
|
||||
let left = expression("(1 - 2) - 3");
|
||||
let right = expression("1 - (2 - 3)");
|
||||
let Kind::Binary {
|
||||
let ExpressionKind::Binary {
|
||||
left, right: last, ..
|
||||
} = left.kind
|
||||
else {
|
||||
@@ -207,13 +207,13 @@ fn unary_literals_precedence_and_comparison_children_keep_distinct_trees() {
|
||||
};
|
||||
assert!(matches!(
|
||||
left.kind,
|
||||
Kind::Binary {
|
||||
ExpressionKind::Binary {
|
||||
op: BinaryOp::Subtract,
|
||||
..
|
||||
}
|
||||
));
|
||||
assert_eq!(number(&last), "3");
|
||||
let Kind::Binary {
|
||||
let ExpressionKind::Binary {
|
||||
left: first, right, ..
|
||||
} = right.kind
|
||||
else {
|
||||
@@ -222,7 +222,7 @@ fn unary_literals_precedence_and_comparison_children_keep_distinct_trees() {
|
||||
assert_eq!(number(&first), "1");
|
||||
assert!(matches!(
|
||||
right.kind,
|
||||
Kind::Binary {
|
||||
ExpressionKind::Binary {
|
||||
op: BinaryOp::Subtract,
|
||||
..
|
||||
}
|
||||
@@ -249,7 +249,7 @@ fn unary_literals_precedence_and_comparison_children_keep_distinct_trees() {
|
||||
#[test]
|
||||
fn every_expression_shape_and_exact_constructor_arity_is_represented() {
|
||||
let tree = expression("if(true, sum([@p, $x], 0), as_kind(@duration, power(abs(-(2)), -2)))");
|
||||
let Kind::If {
|
||||
let ExpressionKind::If {
|
||||
condition,
|
||||
when_true,
|
||||
when_false,
|
||||
@@ -257,24 +257,27 @@ fn every_expression_shape_and_exact_constructor_arity_is_represented() {
|
||||
else {
|
||||
panic!();
|
||||
};
|
||||
assert_eq!(condition.kind, Kind::Boolean(true));
|
||||
let Kind::Sum { values, initial } = when_true.kind else {
|
||||
assert_eq!(condition.kind, ExpressionKind::Boolean(true));
|
||||
let ExpressionKind::Sum { values, initial } = when_true.kind else {
|
||||
panic!();
|
||||
};
|
||||
assert_eq!(number(&initial), "0");
|
||||
let Kind::List(values) = values.kind else {
|
||||
let ExpressionKind::List(values) = values.kind else {
|
||||
panic!();
|
||||
};
|
||||
assert!(matches!(&values[0].kind, Kind::Property(r) if r.name == "p"));
|
||||
assert!(matches!(&values[1].kind, Kind::Parameter(r) if r.name == "x"));
|
||||
let Kind::AsKind { kind, value } = when_false.kind else {
|
||||
assert!(matches!(&values[0].kind, ExpressionKind::Property(r) if r.name == "p"));
|
||||
assert!(matches!(&values[1].kind, ExpressionKind::Parameter(r) if r.name == "x"));
|
||||
let ExpressionKind::AsKind { kind, value } = when_false.kind else {
|
||||
panic!();
|
||||
};
|
||||
assert_eq!(kind.name, "duration");
|
||||
assert!(matches!(value.kind, Kind::Power { exponent: -2, .. }));
|
||||
assert!(matches!(expression("[]").kind, Kind::List(v) if v.is_empty()));
|
||||
assert!(matches!(
|
||||
value.kind,
|
||||
ExpressionKind::Power { exponent: -2, .. }
|
||||
));
|
||||
assert!(matches!(expression("[]").kind, ExpressionKind::List(v) if v.is_empty()));
|
||||
assert!(
|
||||
matches!(expression("@zero()").kind, Kind::Call { arguments, .. } if arguments.is_empty())
|
||||
matches!(expression("@zero()").kind, ExpressionKind::Call { arguments, .. } if arguments.is_empty())
|
||||
);
|
||||
assert!(matches!(
|
||||
parse(" unbound // pending", &mut budget()).unwrap(),
|
||||
@@ -301,17 +304,17 @@ fn every_expression_shape_and_exact_constructor_arity_is_represented() {
|
||||
fn repeated_call_argument_occurrences_have_distinct_original_spans() {
|
||||
let source = "@combine(a: @p, b: 2) + @combine(a: @q, b: 4)";
|
||||
let tree = expression(source);
|
||||
let Kind::Binary { left, right, .. } = tree.kind else {
|
||||
let ExpressionKind::Binary { left, right, .. } = tree.kind else {
|
||||
panic!();
|
||||
};
|
||||
let Kind::Call {
|
||||
let ExpressionKind::Call {
|
||||
definition: first,
|
||||
arguments: a,
|
||||
} = left.kind
|
||||
else {
|
||||
panic!();
|
||||
};
|
||||
let Kind::Call {
|
||||
let ExpressionKind::Call {
|
||||
definition: second,
|
||||
arguments: b,
|
||||
} = right.kind
|
||||
|
||||
Reference in New Issue
Block a user