Skip to content

Commit 4e76f88

Browse files
committed
Support Unary plus operator
1 parent ab5b61f commit 4e76f88

7 files changed

Lines changed: 81 additions & 18 deletions

File tree

crates/gitql-ast/src/operator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[derive(Clone, PartialEq)]
22
pub enum PrefixUnaryOperator {
3-
Negative,
3+
Plus,
4+
Minus,
45
Bang,
56
Not,
67
}

crates/gitql-ast/src/types/base.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,19 @@ pub trait DataType: DynClone {
413413
Box::new(NullType)
414414
}
415415

416+
/// Return a list of types that it's possible to perform unary `+' operator with
417+
/// between current DataType and any one of them
418+
fn can_perform_plus_op(&self) -> bool {
419+
false
420+
}
421+
422+
/// Return the expected type after perform unary `+' operator on current type
423+
///
424+
/// Note that you don't need to check again that the argument type is possible to perform operator with
425+
fn plus_op_result_type(&self) -> Box<dyn DataType> {
426+
Box::new(NullType)
427+
}
428+
416429
/// Return a list of types that it's possible to perform unary `-' operator with
417430
/// between current DataType and any one of them
418431
fn can_perform_neg_op(&self) -> bool {

crates/gitql-ast/src/types/integer.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ impl DataType for IntType {
158158
vec![Box::new(ArrayType::new(Box::new(IntType)))]
159159
}
160160

161+
fn can_perform_plus_op(&self) -> bool {
162+
true
163+
}
164+
165+
fn plus_op_result_type(&self) -> Box<dyn DataType> {
166+
Box::new(self.clone())
167+
}
168+
161169
fn can_perform_neg_op(&self) -> bool {
162170
true
163171
}

crates/gitql-core/src/values/base.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,11 @@ pub trait Value: DynClone {
289289
Err("Unsupported operator for this type".to_string())
290290
}
291291

292+
/// Perform unary `+` operator and return new [`Value`] represent the result or Exception message as [`String`]
293+
fn plus_op(&self) -> Result<Box<dyn Value>, String> {
294+
Err("Unsupported operator for this type".to_string())
295+
}
296+
292297
/// Perform unary `-` operator and return new [`Value`] represent the result or Exception message as [`String`]
293298
fn neg_op(&self) -> Result<Box<dyn Value>, String> {
294299
Err("Unsupported operator for this type".to_string())

crates/gitql-core/src/values/integer.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,12 @@ impl Value for IntValue {
355355
Err("Unexpected type to perform `<=` with".to_string())
356356
}
357357

358+
fn plus_op(&self) -> Result<Box<dyn Value>, String> {
359+
Ok(Box::new(IntValue::new(self.value)))
360+
}
361+
358362
fn neg_op(&self) -> Result<Box<dyn Value>, String> {
359-
Ok(Box::new(IntValue { value: -self.value }))
363+
Ok(Box::new(IntValue::new(-self.value)))
360364
}
361365

362366
fn cast_op(&self, target_type: &Box<dyn DataType>) -> Result<Box<dyn Value>, String> {

crates/gitql-engine/src/engine_evaluator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,8 @@ fn evaluate_prefix_unary(
325325
) -> Result<Box<dyn Value>, String> {
326326
let rhs = evaluate_expression(env, &expr.right, titles, object)?;
327327
match expr.operator {
328-
PrefixUnaryOperator::Negative => rhs.neg_op(),
328+
PrefixUnaryOperator::Plus => rhs.plus_op(),
329+
PrefixUnaryOperator::Minus => rhs.neg_op(),
329330
PrefixUnaryOperator::Bang => rhs.bang_op(),
330331
PrefixUnaryOperator::Not => rhs.not_op(),
331332
}

crates/gitql-parser/src/parser.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,32 +2958,26 @@ fn parse_prefix_unary_expression(
29582958
if *position < tokens.len() && is_prefix_unary_operator(&tokens[*position]) {
29592959
let operator = &tokens[*position];
29602960

2961-
// Consume `!`, `-` or `~` operator
2961+
// Consume `+`, `-`, `!`, `~` operator
29622962
*position += 1;
29632963

29642964
let rhs = parse_prefix_unary_expression(context, env, tokens, position)?;
29652965
let rhs_type = rhs.expr_type();
29662966

2967-
// Parse and Check side for unary `!`or `NOT` operator
2968-
if operator.kind == TokenKind::Bang || operator.kind == TokenKind::Not {
2967+
// Parse and Check side for unary `+` operator
2968+
if operator.kind == TokenKind::Plus {
29692969
// Can perform this operator between RHS
2970-
if rhs_type.can_perform_bang_op() {
2970+
if rhs_type.can_perform_plus_op() {
29712971
return Ok(Box::new(UnaryExpr {
29722972
right: rhs,
2973-
operator: PrefixUnaryOperator::Bang,
2974-
result_type: rhs_type.bang_op_result_type(),
2973+
operator: PrefixUnaryOperator::Plus,
2974+
result_type: rhs_type.neg_op_result_type(),
29752975
}));
29762976
}
29772977

29782978
// Return error if this operator can't be performed even with implicit cast
2979-
let op_name = if operator.kind == TokenKind::Bang {
2980-
"!"
2981-
} else {
2982-
"NOT"
2983-
};
2984-
29852979
return Err(Diagnostic::error(&format!(
2986-
"Operator unary `{op_name}` can't be performed on type `{rhs_type}`"
2980+
"Operator unary `+` can't be performed on type `{rhs_type}`"
29872981
))
29882982
.with_location(operator.location)
29892983
.as_boxed());
@@ -2995,7 +2989,7 @@ fn parse_prefix_unary_expression(
29952989
if rhs_type.can_perform_neg_op() {
29962990
return Ok(Box::new(UnaryExpr {
29972991
right: rhs,
2998-
operator: PrefixUnaryOperator::Negative,
2992+
operator: PrefixUnaryOperator::Minus,
29992993
result_type: rhs_type.neg_op_result_type(),
30002994
}));
30012995
}
@@ -3008,6 +3002,31 @@ fn parse_prefix_unary_expression(
30083002
.as_boxed());
30093003
}
30103004

3005+
// Parse and Check side for unary `!`or `NOT` operator
3006+
if operator.kind == TokenKind::Bang || operator.kind == TokenKind::Not {
3007+
// Can perform this operator between RHS
3008+
if rhs_type.can_perform_bang_op() {
3009+
return Ok(Box::new(UnaryExpr {
3010+
right: rhs,
3011+
operator: PrefixUnaryOperator::Bang,
3012+
result_type: rhs_type.bang_op_result_type(),
3013+
}));
3014+
}
3015+
3016+
// Return error if this operator can't be performed even with implicit cast
3017+
let op_name = if operator.kind == TokenKind::Bang {
3018+
"!"
3019+
} else {
3020+
"NOT"
3021+
};
3022+
3023+
return Err(Diagnostic::error(&format!(
3024+
"Operator unary `{op_name}` can't be performed on type `{rhs_type}`"
3025+
))
3026+
.with_location(operator.location)
3027+
.as_boxed());
3028+
}
3029+
30113030
// Parse and Check side for unary `~` operator
30123031
if operator.kind == TokenKind::BitwiseNot {
30133032
// Can perform this operator between RHS
@@ -3026,6 +3045,14 @@ fn parse_prefix_unary_expression(
30263045
.with_location(operator.location)
30273046
.as_boxed());
30283047
}
3048+
3049+
// Unkown unary operator
3050+
return Err(Diagnostic::error(&format!(
3051+
"Operator unary `{}` is not supported for `{rhs_type}`",
3052+
operator
3053+
))
3054+
.with_location(operator.location)
3055+
.as_boxed());
30293056
}
30303057

30313058
parse_between_expression(context, env, tokens, position)
@@ -4017,7 +4044,11 @@ fn is_bitwise_shift_operator(tokens: &[Token], position: &usize) -> bool {
40174044
fn is_prefix_unary_operator(token: &Token) -> bool {
40184045
matches!(
40194046
token.kind,
4020-
TokenKind::Bang | TokenKind::Not | TokenKind::Minus | TokenKind::BitwiseNot
4047+
TokenKind::Plus
4048+
| TokenKind::Bang
4049+
| TokenKind::Not
4050+
| TokenKind::Minus
4051+
| TokenKind::BitwiseNot
40214052
)
40224053
}
40234054

0 commit comments

Comments
 (0)