diff --git a/formatter/src/code.rs b/formatter/src/code.rs index cb253e79..44185e60 100644 --- a/formatter/src/code.rs +++ b/formatter/src/code.rs @@ -1,7 +1,7 @@ use crate::config::FormattingConfig; use log::trace; -use parser::ast::Expression; +use parser::ast::{Expression, IfConditional}; use tokenizer::tokens::CommentedToken; use crate::format::{Doc, GroupDocProperties, ShouldBreak}; @@ -279,11 +279,121 @@ impl<'a> Code for Expression<'a> { let body_doc = body.to_docs(config); let keyword_plus_args_part = group!(cons!(keyword, args_with_delimiter)); - group!(cons!(keyword_plus_args_part, body_doc), ShouldBreak::Yes) + group!(cons!(keyword_plus_args_part, body_doc), ShouldBreak::No) }, - Expression::IfExpression(_) => todo!() + Expression::IfExpression(if_expression) => { + let (if_conditional, else_ifs, trailing_else) = (&if_expression.if_conditional, &if_expression.else_ifs, &if_expression.trailing_else); + let mut docs = Rc::new(Doc::Nil); + let (conditional_docs, mut conditional_suffix) = if_conditional_to_docs(Rc::new(Doc::Nil), if_conditional, config); + docs = cons!(docs, conditional_docs); + // if (condition) [{] + // body + // } else if(...) { + // } else if(...) { ... + for else_if in else_ifs { + let (&keyword, body) = (&else_if.else_keyword, &else_if.if_conditional); + let prefix = cons!(cons!(conditional_suffix, text!(" ")), keyword.to_docs(config)); + let (else_if_docs, new_suffix) = if_conditional_to_docs(prefix, body, config); + docs = cons!(docs, else_if_docs); + conditional_suffix = new_suffix; + } + if let Some(trailing_else) = trailing_else { + match trailing_else.body.as_ref() { + Expression::Term(term_expr) if term_expr.pre_delimiters.is_some() => { + let mut new_group = cons!(cons!(conditional_suffix, text!(" ")), cons!(trailing_else.else_keyword.to_docs(config), text!(" "))); + match (term_expr.pre_delimiters, term_expr.post_delimiters) { + (Some(pre_delim), Some(post_delim)) => { + if term_expr.term.is_empty() { + conditional_suffix = cons!(new_group, cons!(pre_delim.to_docs(config), post_delim.to_docs(config))); + } else { + new_group = cons!(new_group, pre_delim.to_docs(config)); + new_group = group!(new_group); + new_group = cons!(new_group, nl!(" ")); + let mut body_doc = join_docs( + term_expr.term.iter().map(|t| t.to_docs(config)), + Rc::new(Doc::Nil), + ShouldBreak::Yes, + config, + ); + body_doc = cons!(body_doc, nl!(" ")); + docs = cons!(docs, group!(cons!(new_group, body_doc))); + conditional_suffix = post_delim.to_docs(config); + } + } + _ => panic!("One of the delimiters of the term expression is None: {term_expr:?}"), + } + } + _ => { + conditional_suffix = cons!(conditional_suffix, trailing_else.body.to_docs(config)); + } + } + } + docs = cons!(docs, conditional_suffix); + + docs + } + } + } +} + +fn if_conditional_to_docs( + prefix_docs: Rc, + if_conditional: &IfConditional, + config: &impl FormattingConfig, +) -> (Rc, Rc) { + // docs to append and the suffix doc + let mut docs = group!(cons!( + cons!( + if !matches!(prefix_docs.as_ref(), Doc::Nil) { + cons!(prefix_docs, text!(" ")) + } else { + prefix_docs + }, + cons!(if_conditional.keyword.to_docs(config), text!(" ")) + ), + if_conditional.left_delimiter.to_docs(config) + )); + docs = cons!(docs, nl!("")); + docs = cons!( + docs, + cons!(if_conditional.condition.to_docs(config), nl!("")) + ); + let mut next_group = cons!(if_conditional.right_delimiter.to_docs(config), text!(" ")); + let mut suffix = Rc::new(Doc::Nil); + match if_conditional.body.as_ref() { + Expression::Term(term_expr) if term_expr.pre_delimiters.is_some() => { + match (term_expr.pre_delimiters, term_expr.post_delimiters) { + (Some(pre_delim), Some(post_delim)) => { + if term_expr.term.is_empty() { + next_group = cons!( + next_group, + cons!(pre_delim.to_docs(config), post_delim.to_docs(config)) + ); + } else { + next_group = cons!(next_group, pre_delim.to_docs(config)); + next_group = cons!(next_group, nl!(" ")); + let mut body_doc = join_docs( + term_expr.term.iter().map(|t| t.to_docs(config)), + Rc::new(Doc::Nil), + ShouldBreak::Yes, + config, + ); + body_doc = cons!(body_doc, nl!(" ")); + + next_group = group!(cons!(next_group, body_doc)); + suffix = post_delim.to_docs(config); + } + } + _ => panic!("One of the delimiters of the term expression is None: {term_expr:?}"), + } + } + _ => { + next_group = cons!(next_group, if_conditional.body.to_docs(config)); } } + docs = cons!(docs, next_group); + docs = cons!(docs, nl!("")); + (docs, suffix) } #[cfg(test)] diff --git a/parser/src/token_parsers.rs b/parser/src/token_parsers.rs index 58a12db8..5a2e43b2 100644 --- a/parser/src/token_parsers.rs +++ b/parser/src/token_parsers.rs @@ -28,57 +28,57 @@ token_parser!(lparen, LParen); token_parser!(rparen, RParen); token_parser!(lbrace, LBrace); token_parser!(rbrace, RBrace); -token_parser!(lsubscript, LSubscript); -token_parser!(rsubscript, RSubscript); +// token_parser!(lsubscript, LSubscript); +// token_parser!(rsubscript, RSubscript); token_parser!(comma, Comma); // Reserved -token_parser!(continue_token, Continue); -token_parser!(break_token, Break); +// token_parser!(continue_token, Continue); +// token_parser!(break_token, Break); // Compound token_parser!(if_token, If); token_parser!(else_token, Else); -token_parser!(while_token, While); -token_parser!(for_token, For); -token_parser!(repeat, Repeat); -token_parser!(in_token, In); +// token_parser!(while_token, While); +// token_parser!(for_token, For); +// token_parser!(repeat, Repeat); +// token_parser!(in_token, In); token_parser!(function, Function); -token_parser!(lambda, Lambda); +// token_parser!(lambda, Lambda); // Binary operators -token_parser!(lassign, LAssign); -token_parser!(rassign, RAssign); -token_parser!(old_assign, OldAssign); -token_parser!(equal, Equal); -token_parser!(not_equal, NotEqual); -token_parser!(lower_than, LowerThan); -token_parser!(greater_than, GreaterThan); -token_parser!(lower_equal, LowerEqual); -token_parser!(greater_equal, GreaterEqual); -token_parser!(power, Power); -token_parser!(divide, Divide); -token_parser!(multiply, Multiply); -token_parser!(minus, Minus); -token_parser!(plus, Plus); -token_parser!(help, Help); -token_parser!(and, And); -token_parser!(vectorized_and, VectorizedAnd); -token_parser!(or, Or); -token_parser!(vectorized_or, VectorizedOr); -token_parser!(dollar, Dollar); -token_parser!(pipe, Pipe); -token_parser!(modulo, Modulo); -token_parser!(ns_get, NsGet); -token_parser!(ns_get_int, NsGetInt); -token_parser!(colon, Colon); +// token_parser!(lassign, LAssign); +// token_parser!(rassign, RAssign); +// token_parser!(old_assign, OldAssign); +// token_parser!(equal, Equal); +// token_parser!(not_equal, NotEqual); +// token_parser!(lower_than, LowerThan); +// token_parser!(greater_than, GreaterThan); +// token_parser!(lower_equal, LowerEqual); +// token_parser!(greater_equal, GreaterEqual); +// token_parser!(power, Power); +// token_parser!(divide, Divide); +// token_parser!(multiply, Multiply); +// token_parser!(minus, Minus); +// token_parser!(plus, Plus); +// token_parser!(help, Help); +// token_parser!(and, And); +// token_parser!(vectorized_and, VectorizedAnd); +// token_parser!(or, Or); +// token_parser!(vectorized_or, VectorizedOr); +// token_parser!(dollar, Dollar); +// token_parser!(pipe, Pipe); +// token_parser!(modulo, Modulo); +// token_parser!(ns_get, NsGet); +// token_parser!(ns_get_int, NsGetInt); +// token_parser!(colon, Colon); // Unary operators -token_parser!(unary_not, UnaryNot); +// token_parser!(unary_not, UnaryNot); // Comments -token_parser!(inline_comment, InlineComment(_)); -token_parser!(comment, Comment(_)); +// token_parser!(inline_comment, InlineComment(_)); +// token_parser!(comment, Comment(_)); // EOF token_parser!(eof, EOF); diff --git a/unsully/tests/format_integration.rs b/unsully/tests/format_integration.rs index fc749cd1..ab805f50 100644 --- a/unsully/tests/format_integration.rs +++ b/unsully/tests/format_integration.rs @@ -72,3 +72,11 @@ comparison_test!(function_definition_one_arg_no_body, "013"); comparison_test!(function_definition_tw0_arg_no_body, "014"); comparison_test!(function_definition_one_default_arg_no_body, "015"); comparison_test!(function_definition_three_args_multiline_body, "016"); +comparison_test!(simple_conditional, "017"); +comparison_test!(conditional_with_one_expression_in_body, "018"); +comparison_test!(conditional_with_two_expression_in_body, "019"); +comparison_test!(conditional_with_empty_trailing_else, "020"); +comparison_test!(conditional_with_one_expr_trailing_else, "021"); +comparison_test!(conditional_with_one_expr_and_one_expr_trailing_else, "022"); +comparison_test!(conditional_with_if_else, "023"); +comparison_test!(conditional_with_if_if_else_and_trailing_else, "024"); diff --git a/unsully/tests/test_cases/017.R b/unsully/tests/test_cases/017.R new file mode 100644 index 00000000..0f989150 --- /dev/null +++ b/unsully/tests/test_cases/017.R @@ -0,0 +1 @@ +if(TRUE){} diff --git a/unsully/tests/test_cases/017.expected b/unsully/tests/test_cases/017.expected new file mode 100644 index 00000000..62a887bc --- /dev/null +++ b/unsully/tests/test_cases/017.expected @@ -0,0 +1 @@ +if (TRUE) {} diff --git a/unsully/tests/test_cases/018.R b/unsully/tests/test_cases/018.R new file mode 100644 index 00000000..19bfb965 --- /dev/null +++ b/unsully/tests/test_cases/018.R @@ -0,0 +1 @@ +if(TRUE){7} diff --git a/unsully/tests/test_cases/018.expected b/unsully/tests/test_cases/018.expected new file mode 100644 index 00000000..a23ea83b --- /dev/null +++ b/unsully/tests/test_cases/018.expected @@ -0,0 +1,3 @@ +if (TRUE) { +7 +} diff --git a/unsully/tests/test_cases/019.R b/unsully/tests/test_cases/019.R new file mode 100644 index 00000000..def7c664 --- /dev/null +++ b/unsully/tests/test_cases/019.R @@ -0,0 +1,3 @@ +if(TRUE){ +1 +2} diff --git a/unsully/tests/test_cases/019.expected b/unsully/tests/test_cases/019.expected new file mode 100644 index 00000000..098023ac --- /dev/null +++ b/unsully/tests/test_cases/019.expected @@ -0,0 +1,4 @@ +if (TRUE) { +1 +2 +} diff --git a/unsully/tests/test_cases/020.R b/unsully/tests/test_cases/020.R new file mode 100644 index 00000000..9b5fd9b2 --- /dev/null +++ b/unsully/tests/test_cases/020.R @@ -0,0 +1 @@ +if(TRUE){}else{} diff --git a/unsully/tests/test_cases/020.expected b/unsully/tests/test_cases/020.expected new file mode 100644 index 00000000..c8879949 --- /dev/null +++ b/unsully/tests/test_cases/020.expected @@ -0,0 +1 @@ +if (TRUE) {} else {} diff --git a/unsully/tests/test_cases/021.R b/unsully/tests/test_cases/021.R new file mode 100644 index 00000000..8026d81e --- /dev/null +++ b/unsully/tests/test_cases/021.R @@ -0,0 +1 @@ +if(TRUE){}else{7} diff --git a/unsully/tests/test_cases/021.expected b/unsully/tests/test_cases/021.expected new file mode 100644 index 00000000..e9cd6e8d --- /dev/null +++ b/unsully/tests/test_cases/021.expected @@ -0,0 +1,3 @@ +if (TRUE) {} else { +7 +} diff --git a/unsully/tests/test_cases/022.R b/unsully/tests/test_cases/022.R new file mode 100644 index 00000000..cc0a8bac --- /dev/null +++ b/unsully/tests/test_cases/022.R @@ -0,0 +1 @@ +if(TRUE){1}else{7} diff --git a/unsully/tests/test_cases/022.expected b/unsully/tests/test_cases/022.expected new file mode 100644 index 00000000..03ddfdd7 --- /dev/null +++ b/unsully/tests/test_cases/022.expected @@ -0,0 +1,5 @@ +if (TRUE) { +1 +} else { +7 +} diff --git a/unsully/tests/test_cases/023.R b/unsully/tests/test_cases/023.R new file mode 100644 index 00000000..ec298bde --- /dev/null +++ b/unsully/tests/test_cases/023.R @@ -0,0 +1 @@ +if (TRUE) {} else if (FALSE) {} diff --git a/unsully/tests/test_cases/023.expected b/unsully/tests/test_cases/023.expected new file mode 100644 index 00000000..ec298bde --- /dev/null +++ b/unsully/tests/test_cases/023.expected @@ -0,0 +1 @@ +if (TRUE) {} else if (FALSE) {} diff --git a/unsully/tests/test_cases/024.R b/unsully/tests/test_cases/024.R new file mode 100644 index 00000000..1c844fa3 --- /dev/null +++ b/unsully/tests/test_cases/024.R @@ -0,0 +1 @@ +if (TRUE) {1} else if (FALSE) {3} else {2} diff --git a/unsully/tests/test_cases/024.expected b/unsully/tests/test_cases/024.expected new file mode 100644 index 00000000..81131abb --- /dev/null +++ b/unsully/tests/test_cases/024.expected @@ -0,0 +1,7 @@ +if (TRUE) { +1 +} else if (FALSE) { +3 +} else { +2 +}