Skip to content

Commit

Permalink
feat: added unary operator support for parsing and formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
kpagacz committed Sep 14, 2024
1 parent 91faf53 commit c258ca9
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 27 deletions.
1 change: 1 addition & 0 deletions formatter/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ impl<'a> Code for Expression<'a> {
}
_ => panic!("Term with not matching delimiters found"),
},
Expression::Unary(op, expr) => op.to_docs(config).cons(expr.to_docs(config)),
Expression::Bop(op, lhs, rhs) => match op.token {
Token::LAssign
| Token::RAssign
Expand Down
2 changes: 2 additions & 0 deletions parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub enum Expression<'a> {
Literal(&'a CommentedToken<'a>),
Comment(&'a CommentedToken<'a>),
Term(Box<TermExpr<'a>>),
Unary(&'a CommentedToken<'a>, Box<Expression<'a>>),
Bop(
&'a CommentedToken<'a>,
Box<Expression<'a>>,
Expand Down Expand Up @@ -33,6 +34,7 @@ impl std::fmt::Display for Expression<'_> {
Expression::Literal(token) => f.write_fmt(format_args!("{}", TokensBuffer(&[token]))),
Expression::Comment(token) => f.write_fmt(format_args!("{}", TokensBuffer(&[token]))),
Expression::Term(term) => f.write_fmt(format_args!("{}", term)),
Expression::Unary(op, expr) => f.write_fmt(format_args!("{}{}", op, expr)),
Expression::Bop(op, left, right) => {
f.write_fmt(format_args!("{} {} {}", left, TokensBuffer(&[op]), right))
}
Expand Down
17 changes: 15 additions & 2 deletions parser/src/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ enum Tail<'a> {
SingleSubset(Args<'a>),
}

fn unary_op<'a, 'b: 'a>(tokens: Input<'a, 'b>) -> IResult<Input<'a, 'b>, &'b CommentedToken<'a>> {
alt((minus, plus, unary_not))(tokens)
}

fn unary_term<'a, 'b: 'a>(tokens: Input<'a, 'b>) -> IResult<Input<'a, 'b>, Expression<'a>> {
alt((
map(tuple((unary_op, atomic_term)), |(op, term)| {
Expression::Unary(op, Box::new(term))
}),
atomic_term,
))(tokens)
}

pub(crate) fn atomic_term<'a, 'b: 'a>(
tokens: Input<'a, 'b>,
) -> IResult<Input<'a, 'b>, Expression<'a>> {
Expand Down Expand Up @@ -242,7 +255,7 @@ impl ExprParser {
while is_binary_operator(lookahead) && precedence(lookahead) >= self.0 {
let op = lookahead;
tokens = &tokens[1..];
let (new_tokens, mut rhs) = atomic_term(tokens)?;
let (new_tokens, mut rhs) = unary_term(tokens)?;
tokens = new_tokens;
lookahead = &tokens[0];
while is_binary_operator(lookahead)
Expand Down Expand Up @@ -272,7 +285,7 @@ impl ExprParser {

pub(crate) fn expr<'a, 'b: 'a>(tokens: Input<'a, 'b>) -> IResult<Input<'a, 'b>, Expression<'a>> {
trace!("expr: {}", TokensBuffer(tokens));
let (tokens, term) = atomic_term(tokens)?;
let (tokens, term) = unary_term(tokens)?;
if !tokens.is_empty() {
let parser = ExprParser(0);
parser.parse(term, tokens)
Expand Down
6 changes: 3 additions & 3 deletions parser/src/token_parsers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ token_parser!(lambda, Lambda);
// 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);
Expand All @@ -76,7 +74,9 @@ token_parser!(lambda, Lambda);
// token_parser!(colon, Colon);

// Unary operators
// token_parser!(unary_not, UnaryNot);
token_parser!(unary_not, UnaryNot);
token_parser!(minus, Minus);
token_parser!(plus, Plus);

// Comments
// token_parser!(inline_comment, InlineComment(_));
Expand Down
1 change: 1 addition & 0 deletions unsully/tests/format_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,5 @@ comparison_test!(two_line_leading_comment, "060");
comparison_test!(two_line_with_short_line_config, "060", short_line_config());
comparison_test!(two_leading_comments_one_after_another, "061");
comparison_test!(comments_with_no_code_work, "062");
comparison_test!(parsing_unary_operators, "063");
comparison_test!(real_life_example_0, "real_life_0");
2 changes: 2 additions & 0 deletions unsully/tests/test_cases/063.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-1
!TRUE
2 changes: 2 additions & 0 deletions unsully/tests/test_cases/063.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-1
!TRUE
46 changes: 24 additions & 22 deletions unsully/tests/test_cases/real_life_0.expected
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
rows <- lapply(
datanames,
function(dataname) {
parent <- teal.data::parent(joinkeys, dataname)
rows <-
lapply(
datanames,
function(dataname) {
parent <- teal.data::parent(joinkeys, dataname)

# todo: what should we display for a parent dataset?
# - Obs and Subjects
# - Obs only
# - Subjects only
# todo (for later): summary table should be displayed in a way that child datasets
# are indented under their parent dataset to form a tree structure
subject_keys <- if (length(parent) > 0) {
names(joinkeys[dataname, parent])
} else {
joinkeys[dataname, dataname]
}
get_object_filter_overview(
filtered_data = filtered_data_objs[[dataname]],
unfiltered_data = unfiltered_data_objs[[dataname]],
dataname = dataname,
subject_keys = subject_keys
)
}
# todo: what should we display for a parent dataset?
# - Obs and Subjects
# - Obs only
# - Subjects only
# todo (for later): summary table should be displayed in a way that child datasets
# are indented under their parent dataset to form a tree structure
subject_keys <-
if (length(parent) > 0) {
names(joinkeys[dataname, parent])
} else {
joinkeys[dataname, dataname]
}
get_object_filter_overview(
filtered_data = filtered_data_objs[[dataname]],
unfiltered_data = unfiltered_data_objs[[dataname]],
dataname = dataname,
subject_keys = subject_keys
)
}
)

unssuported_idx <- vapply(rows, function(x) all(is.na(x[-1])), logical(1)) # this is mainly for vectors

0 comments on commit c258ca9

Please sign in to comment.