diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c28dca344804..b8bf7011099f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ - [Visualizations on components are slightly transparent when not focused][11582]. - [New design for vector-editing widget][11620] +- [The `:` type operator can now be chained][11671] [11151]: https://github.com/enso-org/enso/pull/11151 [11271]: https://github.com/enso-org/enso/pull/11271 @@ -60,6 +61,7 @@ [11612]: https://github.com/enso-org/enso/pull/11612 [11582]: https://github.com/enso-org/enso/pull/11582 [11620]: https://github.com/enso-org/enso/pull/11620 +[11671]: https://github.com/enso-org/enso/pull/11671 #### Enso Standard Library diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso index f1fe3b3855067..669268ca9273a 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso @@ -83,7 +83,7 @@ type Table_Column_Helper specified types will also be selected (i.e. ignore size, precision). select_by_type : Vector Value_Type -> Boolean -> Vector select_by_type self types:Vector strict:Boolean=False = - parsed_types = types.map t->t:Value_Type + parsed_types = types.map t-> t:Value_Type selected_columns = if strict then self.columns.filter c-> parsed_types.contains c.value_type else self.columns.filter c-> parsed_types.any t-> c.value_type.is_same_type t if selected_columns.length == 0 then Error.throw (No_Output_Columns.Error "No columns of the specified types were found.") else diff --git a/lib/rust/parser/debug/tests/parse.rs b/lib/rust/parser/debug/tests/parse.rs index 2dcbd876d9bf9..996461727d26d 100644 --- a/lib/rust/parser/debug/tests/parse.rs +++ b/lib/rust/parser/debug/tests/parse.rs @@ -1053,6 +1053,14 @@ fn type_signatures() { fn type_annotations() { test_block!("val = x : Int", ,(Assignment::new("val", sexp![(TypeAnnotated (Ident x) ":" (Ident Int))]))); + test_block!("val = x : A : B : C", + ,(Assignment::new("val", sexp![ + (TypeAnnotated + (TypeAnnotated + (TypeAnnotated (Ident x) + ":" (Ident A)) + ":" (Ident B)) + ":" (Ident C))]))); test_block!("val = foo (x : Int)", ,(Assignment::new("val", sexp![ (App (Ident foo) diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index 49117ef7e0da4..6f1dcd0307463 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -686,16 +686,22 @@ fn analyze_operator(token: &str) -> token::Variant { pub fn analyze_non_syntactic_operator(token: &str) -> OperatorProperties { match token { "-" => OperatorProperties::value() - .with_unary_prefix_mode(token::Precedence::unary_minus()) - .with_binary_infix_precedence(15), - "!" => OperatorProperties::value().with_binary_infix_precedence(3), - "||" | "\\\\" | "&&" => OperatorProperties::value().with_binary_infix_precedence(4), - ">>" | "<<" => OperatorProperties::functional().with_binary_infix_precedence(5), - "|>" | "|>>" => OperatorProperties::functional().with_binary_infix_precedence(6), - "<|" | "<<|" => - OperatorProperties::functional().with_binary_infix_precedence(6).as_right_associative(), - "<=" | ">=" => OperatorProperties::value().with_binary_infix_precedence(14), - "==" | "!=" => OperatorProperties::value().with_binary_infix_precedence(5), + .with_unary_prefix_mode(token::Precedence::Negation) + .with_binary_infix_precedence(token::Precedence::Addition), + "!" => OperatorProperties::value().with_binary_infix_precedence(token::Precedence::Not), + "||" | "\\\\" | "&&" => + OperatorProperties::value().with_binary_infix_precedence(token::Precedence::Logical), + ">>" | "<<" => OperatorProperties::functional() + .with_binary_infix_precedence(token::Precedence::Equality), + "|>" | "|>>" => OperatorProperties::functional() + .with_binary_infix_precedence(token::Precedence::Functional), + "<|" | "<<|" => OperatorProperties::functional() + .with_binary_infix_precedence(token::Precedence::Functional) + .as_right_associative(), + "<=" | ">=" => + OperatorProperties::value().with_binary_infix_precedence(token::Precedence::Inequality), + "==" | "!=" => + OperatorProperties::value().with_binary_infix_precedence(token::Precedence::Equality), _ => analyze_user_operator(token), } } @@ -725,14 +731,14 @@ fn analyze_user_operator(token: &str) -> OperatorProperties { } } let binary = match precedence_char.unwrap() { - '!' => 10, - '|' => 11, - '&' => 13, - '<' | '>' => 14, - '+' | '-' => 15, - '*' | '/' | '%' => 16, - '^' => 17, - _ => 18, + '!' => token::Precedence::Not, + '|' => token::Precedence::BitwiseOr, + '&' => token::Precedence::BitwiseAnd, + '<' | '>' => token::Precedence::Inequality, + '+' | '-' => token::Precedence::Addition, + '*' | '/' | '%' => token::Precedence::Multiplication, + '^' => token::Precedence::Exponentiation, + _ => token::Precedence::OtherUserOperator, }; operator = operator.with_binary_infix_precedence(binary); if !has_right_arrow && !has_left_arrow { diff --git a/lib/rust/parser/src/syntax/operator/annotations.rs b/lib/rust/parser/src/syntax/operator/annotations.rs index b3c09e5244fc8..ce5c950bc5a4f 100644 --- a/lib/rust/parser/src/syntax/operator/annotations.rs +++ b/lib/rust/parser/src/syntax/operator/annotations.rs @@ -86,7 +86,7 @@ where Inner: left_precedence: None, right_precedence: ModifiedPrecedence::new( following_spacing.unwrap_or_default(), - Precedence::annotation(), + Precedence::Negation, false, ), associativity: Associativity::Left, diff --git a/lib/rust/parser/src/syntax/operator/application.rs b/lib/rust/parser/src/syntax/operator/application.rs index e876196b0e091..a4278aaf4cc0a 100644 --- a/lib/rust/parser/src/syntax/operator/application.rs +++ b/lib/rust/parser/src/syntax/operator/application.rs @@ -42,13 +42,13 @@ where Inner: OperatorConsumer<'s> + OperandConsumer<'s> Spacing::of_token(&name) }; let precedence = - ModifiedPrecedence::new(spacing, token::Precedence::application(), false); + ModifiedPrecedence::new(spacing, token::Precedence::Application, false); let right_precedence = ModifiedPrecedence::new( // Named applications always have unspaced right-precedence; if it reads // from left to right as a named application, a following operator can't // cause the interpretation to change. Spacing::Unspaced, - token::Precedence::application(), + token::Precedence::Application, false, ); let operator = Operator { @@ -105,7 +105,7 @@ impl Finish for InsertApps { } fn application<'s>(spacing: Spacing) -> Operator<'s> { - let precedence = ModifiedPrecedence::new(spacing, token::Precedence::application(), false); + let precedence = ModifiedPrecedence::new(spacing, token::Precedence::Application, false); Operator { left_precedence: Some(precedence), right_precedence: precedence, diff --git a/lib/rust/parser/src/syntax/token/operator.rs b/lib/rust/parser/src/syntax/token/operator.rs index 5a75721a5c137..92fcc3415cf58 100644 --- a/lib/rust/parser/src/syntax/token/operator.rs +++ b/lib/rust/parser/src/syntax/token/operator.rs @@ -45,11 +45,7 @@ impl OperatorProperties { } /// Return a copy of this operator, with the given binary infix precedence. - pub fn with_binary_infix_precedence(self, value: u8) -> Self { - let precedence = Precedence { value }; - debug_assert!(precedence > Precedence::min()); - debug_assert!(value & 0x80 == 0); - debug_assert!((value + 1) & 0x80 == 0); + pub fn with_binary_infix_precedence(self, precedence: Precedence) -> Self { Self { binary_infix_precedence: Some(precedence), ..self } } @@ -159,7 +155,7 @@ impl<'s> TokenOperatorProperties for Token<'s> { impl HasOperatorProperties for variant::AssignmentOperator { fn operator_properties(&self) -> OperatorProperties { OperatorProperties { - binary_infix_precedence: Some(Precedence { value: 1 }), + binary_infix_precedence: Some(Precedence::Assignment), lhs_section_termination: Some(SectionTermination::Unwrap), is_right_associative: true, is_compile_time: true, @@ -171,9 +167,8 @@ impl HasOperatorProperties for variant::AssignmentOperator { impl HasOperatorProperties for variant::TypeAnnotationOperator { fn operator_properties(&self) -> OperatorProperties { OperatorProperties { - binary_infix_precedence: Some(Precedence { value: 2 }), + binary_infix_precedence: Some(Precedence::TypeAnnotation), lhs_section_termination: Some(SectionTermination::Reify), - is_right_associative: true, is_compile_time: true, rhs_is_non_expression: true, ..default() @@ -184,7 +179,7 @@ impl HasOperatorProperties for variant::TypeAnnotationOperator { impl HasOperatorProperties for variant::ArrowOperator { fn operator_properties(&self) -> OperatorProperties { OperatorProperties { - binary_infix_precedence: Some(Precedence { value: 2 }), + binary_infix_precedence: Some(Precedence::Arrow), lhs_section_termination: Some(SectionTermination::Unwrap), is_right_associative: true, is_compile_time: true, @@ -196,7 +191,7 @@ impl HasOperatorProperties for variant::ArrowOperator { impl HasOperatorProperties for variant::AnnotationOperator { fn operator_properties(&self) -> OperatorProperties { OperatorProperties { - unary_prefix_precedence: Some(Precedence::max()), + unary_prefix_precedence: Some(Precedence::Annotation), is_right_associative: true, is_compile_time: true, rhs_is_non_expression: true, @@ -220,7 +215,7 @@ impl HasOperatorProperties for variant::NegationOperator { fn operator_properties(&self) -> OperatorProperties { OperatorProperties { is_value_operation: true, - unary_prefix_precedence: Some(Precedence::unary_minus()), + unary_prefix_precedence: Some(Precedence::Negation), ..default() } } @@ -238,7 +233,7 @@ impl HasOperatorProperties for variant::LambdaOperator { impl HasOperatorProperties for variant::DotOperator { fn operator_properties(&self) -> OperatorProperties { - OperatorProperties { binary_infix_precedence: Some(Precedence { value: 80 }), ..default() } + OperatorProperties { binary_infix_precedence: Some(Precedence::Application), ..default() } } } @@ -256,7 +251,7 @@ impl HasOperatorProperties for variant::SuspensionOperator { impl HasOperatorProperties for variant::CommaOperator { fn operator_properties(&self) -> OperatorProperties { OperatorProperties { - binary_infix_precedence: Some(Precedence { value: 1 }), + binary_infix_precedence: Some(Precedence::Assignment), is_compile_time: true, rhs_is_non_expression: true, ..default() @@ -267,50 +262,56 @@ impl HasOperatorProperties for variant::CommaOperator { /// Value that can be compared to determine which operator will bind more tightly within an /// expression. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Precedence { - /// A numeric value determining precedence order. - pub(super) value: u8, +#[repr(u8)] +#[allow(missing_docs)] +pub enum Precedence { + /// A value that is lower than the precedence of any operator. + Min = 0, + Assignment, + TypeAnnotation, + Arrow, + Not, + Logical, + Equality, + Functional, + BitwiseOr, + BitwiseAnd, + Inequality, + Addition, + Multiplication, + Exponentiation, + OtherUserOperator, + Negation, + Application, + Annotation, + /// A value that is higher than the precedence of any operator. + Max, } impl Precedence { /// Return a precedence that is lower than the precedence of any operator. pub fn min() -> Self { - Precedence { value: 0 } + Precedence::Min } - /// Return the precedence for any operator. + /// Return the lowest precedence for any operator. pub fn min_valid() -> Self { - Precedence { value: 1 } + debug_assert_eq!(Precedence::Assignment as u8, Precedence::Min as u8 + 1); + Precedence::Assignment } /// Return a precedence that is not lower than any other precedence. pub fn max() -> Self { - Precedence { value: 100 } - } - - /// Return the precedence of application. - pub fn application() -> Self { - Precedence { value: 80 } - } - - /// Return the precedence of @annotations. - pub fn annotation() -> Self { - Precedence { value: 79 } - } - - /// Return the precedence of unary minus. - pub fn unary_minus() -> Self { - Precedence { value: 79 } - } - - /// Return the precedence of unary minus when applied to a numeric literal. - pub fn unary_minus_numeric_literal() -> Self { - Precedence { value: 80 } + Precedence::Max } /// Return the value as a number. pub fn into_u8(self) -> u8 { - self.value + let value = self as u8; + debug_assert!(value > Precedence::Min as u8); + debug_assert!(value & 0x80 == 0); + debug_assert!((value + 1) & 0x80 == 0); + value } }