diff --git a/crates/oa-core/src/language/analysis_source.rs b/crates/oa-core/src/language/analysis_source.rs index 1a857522..425e4cb2 100644 --- a/crates/oa-core/src/language/analysis_source.rs +++ b/crates/oa-core/src/language/analysis_source.rs @@ -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, } #[derive(Debug, PartialEq, Eq)] -pub enum Kind { +pub enum ExpressionKind { Boolean(bool), Number(Exact), Quantity { diff --git a/crates/oa-core/src/language/analysis_source/syntax.rs b/crates/oa-core/src/language/analysis_source/syntax.rs index 981bc061..489bb1bb 100644 --- a/crates/oa-core/src/language/analysis_source/syntax.rs +++ b/crates/oa-core/src/language/analysis_source/syntax.rs @@ -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 { + fn node(&mut self, kind: ExpressionKind, span: Span) -> Result { 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 { diff --git a/crates/oa-core/src/language/analysis_source/tests.rs b/crates/oa-core/src/language/analysis_source/tests.rs index 4ca3b73e..b1c9bc3f 100644 --- a/crates/oa-core/src/language/analysis_source/tests.rs +++ b/crates/oa-core/src/language/analysis_source/tests.rs @@ -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::>(), ["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