Skip to content

Commit bcd2247

Browse files
committed
Implement Row type and value
1 parent 61413c1 commit bcd2247

8 files changed

Lines changed: 223 additions & 20 deletions

File tree

crates/gitql-ast/src/expression.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::operator::GroupComparisonOperator;
1818
use crate::operator::PrefixUnaryOperator;
1919
use crate::types::float::FloatType;
2020
use crate::types::interval::IntervalType;
21+
use crate::types::row::RowType;
2122

2223
#[derive(PartialEq)]
2324
pub enum ExprKind {
@@ -50,7 +51,8 @@ pub enum ExprKind {
5051
IsNull,
5152
Null,
5253
Cast,
53-
Grouping,
54+
Column,
55+
Row,
5456
MemberAccess,
5557
}
5658

@@ -711,13 +713,13 @@ impl Expr for CastExpr {
711713
}
712714

713715
#[derive(Clone)]
714-
pub struct GroupExpr {
716+
pub struct ColumnExpr {
715717
pub expr: Box<dyn Expr>,
716718
}
717719

718-
impl Expr for GroupExpr {
720+
impl Expr for ColumnExpr {
719721
fn kind(&self) -> ExprKind {
720-
ExprKind::Grouping
722+
ExprKind::Column
721723
}
722724

723725
fn expr_type(&self) -> Box<dyn DataType> {
@@ -729,6 +731,26 @@ impl Expr for GroupExpr {
729731
}
730732
}
731733

734+
#[derive(Clone)]
735+
pub struct RowExpr {
736+
pub exprs: Vec<Box<dyn Expr>>,
737+
pub row_type: RowType,
738+
}
739+
740+
impl Expr for RowExpr {
741+
fn kind(&self) -> ExprKind {
742+
ExprKind::Row
743+
}
744+
745+
fn expr_type(&self) -> Box<dyn DataType> {
746+
Box::new(self.row_type.clone())
747+
}
748+
749+
fn as_any(&self) -> &dyn Any {
750+
self
751+
}
752+
}
753+
732754
#[derive(Clone)]
733755
pub struct MemberAccessExpr {
734756
pub composite: Box<dyn Expr>,

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::fmt;
44
use dyn_clone::DynClone;
55

66
use crate::expression::Expr;
7+
use crate::types::row::RowType;
78

89
use super::any::AnyType;
910
use super::array::ArrayType;
@@ -589,6 +590,11 @@ impl dyn DataType {
589590
self.as_any().downcast_ref::<VarargsType>().is_some()
590591
}
591592

593+
/// Return true if this type is [`RowType`]
594+
pub fn is_row(&self) -> bool {
595+
self.as_any().downcast_ref::<RowType>().is_some()
596+
}
597+
592598
/// Return true if this type is [`CompositeType`]
593599
pub fn is_composite(&self) -> bool {
594600
self.as_any().downcast_ref::<CompositeType>().is_some()

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub mod interval;
1111
pub mod null;
1212
pub mod optional;
1313
pub mod range;
14+
pub mod row;
1415
pub mod text;
1516
pub mod time;
1617
pub mod undefined;

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::any::Any;
2+
3+
use super::base::DataType;
4+
5+
#[derive(Clone)]
6+
pub struct RowType {
7+
pub tuple: Vec<Box<dyn DataType>>,
8+
}
9+
10+
impl RowType {
11+
pub fn new(tuple: Vec<Box<dyn DataType>>) -> Self {
12+
RowType { tuple }
13+
}
14+
}
15+
16+
impl DataType for RowType {
17+
fn literal(&self) -> String {
18+
let mut str = String::new();
19+
let last_position = self.tuple.len() - 1;
20+
str += "Row(";
21+
for (pos, data_type) in self.tuple.iter().enumerate() {
22+
str += &data_type.literal();
23+
if pos != last_position {
24+
str += ", ";
25+
}
26+
}
27+
str += ")";
28+
str
29+
}
30+
31+
fn equals(&self, other: &Box<dyn DataType>) -> bool {
32+
let row_type: Box<dyn DataType> = Box::new(self.clone());
33+
if other.is_any() || other.is_variant_contains(&row_type) {
34+
return true;
35+
}
36+
37+
if let Some(other_row) = other.as_any().downcast_ref::<RowType>() {
38+
if self.tuple.len() != other_row.tuple.len() {
39+
return false;
40+
}
41+
42+
let len = self.tuple.len();
43+
for i in 0..len {
44+
if !self.tuple[i].eq(&other_row.tuple[i]) {
45+
return false;
46+
}
47+
}
48+
49+
return true;
50+
}
51+
52+
false
53+
}
54+
55+
fn as_any(&self) -> &dyn Any {
56+
self
57+
}
58+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod integer;
99
pub mod interval;
1010
pub mod null;
1111
pub mod range;
12+
pub mod row;
1213
pub mod text;
1314
pub mod time;
1415

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use std::any::Any;
2+
use std::cmp::Ordering;
3+
4+
use gitql_ast::types::row::RowType;
5+
use gitql_ast::types::DataType;
6+
7+
use super::base::Value;
8+
9+
#[derive(Clone)]
10+
pub struct RowValue {
11+
pub columns: Vec<Box<dyn Value>>,
12+
pub row_type: RowType,
13+
}
14+
15+
impl RowValue {
16+
pub fn new(columns: Vec<Box<dyn Value>>, row_type: RowType) -> Self {
17+
RowValue { columns, row_type }
18+
}
19+
}
20+
21+
impl Value for RowValue {
22+
fn literal(&self) -> String {
23+
let mut str = String::new();
24+
str += "(";
25+
for (pos, element) in self.columns.iter().enumerate() {
26+
str += &element.literal();
27+
if pos + 1 != self.columns.len() {
28+
str += ", ";
29+
}
30+
}
31+
str += ")";
32+
str
33+
}
34+
35+
fn equals(&self, other: &Box<dyn Value>) -> bool {
36+
if let Some(other_row) = other.as_any().downcast_ref::<RowValue>() {
37+
let data_type: Box<dyn DataType> = Box::new(other_row.row_type.clone());
38+
if !self.row_type.equals(&data_type) {
39+
return false;
40+
}
41+
42+
let len = self.row_type.tuple.len();
43+
for i in 0..len {
44+
if !self.columns[i].eq(&other_row.columns[i]) {
45+
return false;
46+
}
47+
}
48+
49+
return true;
50+
}
51+
false
52+
}
53+
54+
fn compare(&self, _other: &Box<dyn Value>) -> Option<Ordering> {
55+
None
56+
}
57+
58+
fn data_type(&self) -> Box<dyn DataType> {
59+
Box::new(self.row_type.clone())
60+
}
61+
62+
fn as_any(&self) -> &dyn Any {
63+
self
64+
}
65+
}

crates/gitql-engine/src/engine_evaluator.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use gitql_ast::expression::BooleanExpr;
99
use gitql_ast::expression::CallExpr;
1010
use gitql_ast::expression::CaseExpr;
1111
use gitql_ast::expression::CastExpr;
12+
use gitql_ast::expression::ColumnExpr;
1213
use gitql_ast::expression::ComparisonExpr;
1314
use gitql_ast::expression::ContainedByExpr;
1415
use gitql_ast::expression::ContainsExpr;
@@ -17,7 +18,6 @@ use gitql_ast::expression::ExprKind::*;
1718
use gitql_ast::expression::GlobExpr;
1819
use gitql_ast::expression::GlobalVariableExpr;
1920
use gitql_ast::expression::GroupComparisonExpr;
20-
use gitql_ast::expression::GroupExpr;
2121
use gitql_ast::expression::InExpr;
2222
use gitql_ast::expression::IndexExpr;
2323
use gitql_ast::expression::IntervalExpr;
@@ -28,6 +28,7 @@ use gitql_ast::expression::MemberAccessExpr;
2828
use gitql_ast::expression::Number;
2929
use gitql_ast::expression::NumberExpr;
3030
use gitql_ast::expression::RegexExpr;
31+
use gitql_ast::expression::RowExpr;
3132
use gitql_ast::expression::SliceExpr;
3233
use gitql_ast::expression::StringExpr;
3334
use gitql_ast::expression::SymbolExpr;
@@ -45,6 +46,7 @@ use gitql_core::values::float::FloatValue;
4546
use gitql_core::values::integer::IntValue;
4647
use gitql_core::values::interval::IntervalValue;
4748
use gitql_core::values::null::NullValue;
49+
use gitql_core::values::row::RowValue;
4850
use gitql_core::values::text::TextValue;
4951
use gitql_core::values::Value;
5052

@@ -192,9 +194,13 @@ pub fn evaluate_expression(
192194
let expr = expression.as_any().downcast_ref::<CastExpr>().unwrap();
193195
evaluate_cast(env, expr, titles, object)
194196
}
195-
Grouping => {
196-
let expr = expression.as_any().downcast_ref::<GroupExpr>().unwrap();
197-
evaluate_grouping(env, expr, titles, object)
197+
Column => {
198+
let expr = expression.as_any().downcast_ref::<ColumnExpr>().unwrap();
199+
evaluate_column(env, expr, titles, object)
200+
}
201+
Row => {
202+
let expr = expression.as_any().downcast_ref::<RowExpr>().unwrap();
203+
evaluate_row(env, expr, titles, object)
198204
}
199205
MemberAccess => {
200206
let expr = expression
@@ -590,16 +596,29 @@ fn evaluate_cast(
590596
value.cast_op(&expr.result_type)
591597
}
592598

593-
fn evaluate_grouping(
599+
fn evaluate_column(
594600
env: &mut Environment,
595-
expr: &GroupExpr,
601+
expr: &ColumnExpr,
596602
titles: &[String],
597603
object: &Vec<Box<dyn Value>>,
598604
) -> Result<Box<dyn Value>, String> {
599605
let value = evaluate_expression(env, &expr.expr, titles, object)?;
600606
Ok(value)
601607
}
602608

609+
fn evaluate_row(
610+
env: &mut Environment,
611+
expr: &RowExpr,
612+
titles: &[String],
613+
object: &Vec<Box<dyn Value>>,
614+
) -> Result<Box<dyn Value>, String> {
615+
let mut values = Vec::with_capacity(expr.exprs.len());
616+
for column in expr.exprs.iter() {
617+
values.push(evaluate_expression(env, column, titles, object)?);
618+
}
619+
Ok(Box::new(RowValue::new(values, expr.row_type.to_owned())))
620+
}
621+
603622
fn evaluate_member_access(
604623
env: &mut Environment,
605624
expr: &MemberAccessExpr,

crates/gitql-parser/src/parser.rs

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use gitql_ast::types::any::AnyType;
2121
use gitql_ast::types::array::ArrayType;
2222
use gitql_ast::types::boolean::BoolType;
2323
use gitql_ast::types::composite::CompositeType;
24+
use gitql_ast::types::row::RowType;
2425
use gitql_ast::types::undefined::UndefType;
2526
use gitql_ast::types::DataType;
2627
use gitql_core::environment::Environment;
@@ -3396,7 +3397,7 @@ pub(crate) fn parse_member_access_expression(
33963397

33973398
// The syntax for member access is (composite).member
33983399
// The composite expr must be in group, that make it different from table access table.name
3399-
if expr.kind() != ExprKind::Grouping {
3400+
if expr.kind() != ExprKind::Column {
34003401
return Err(
34013402
Diagnostic::error("Dot token expect composite value between `(` and `)`")
34023403
.add_note("The syntax for accessing composite element is (composite).member")
@@ -3474,7 +3475,7 @@ fn parse_primary_expression(
34743475
TokenKind::Symbol(_) => parse_symbol_expression(context, env, tokens, position),
34753476
TokenKind::Array => parse_array_value_expression(context, env, tokens, position),
34763477
TokenKind::LeftBracket => parse_array_value_expression(context, env, tokens, position),
3477-
TokenKind::LeftParen => parse_group_expression(context, env, tokens, position),
3478+
TokenKind::LeftParen => parse_column_or_row_expression(context, env, tokens, position),
34783479
TokenKind::Case => parse_case_expression(context, env, tokens, position),
34793480
TokenKind::Cast => parse_cast_call_expression(context, env, tokens, position),
34803481
TokenKind::Benchmark => parse_benchmark_call_expression(context, env, tokens, position),
@@ -3721,27 +3722,57 @@ fn parse_array_value_expression(
37213722
}))
37223723
}
37233724

3724-
fn parse_group_expression(
3725+
fn parse_column_or_row_expression(
37253726
context: &mut ParserContext,
37263727
env: &mut Environment,
37273728
tokens: &[Token],
37283729
position: &mut usize,
37293730
) -> Result<Box<dyn Expr>, Box<Diagnostic>> {
37303731
// Consume '(' token
3731-
*position += 1;
3732+
consume_token_or_error(
3733+
tokens,
3734+
position,
3735+
TokenKind::LeftParen,
3736+
"Expect `(` at the start of column or row expression",
3737+
)?;
37323738

3733-
let expression = parse_expression(context, env, tokens, position)?;
3734-
if tokens[*position].kind != TokenKind::RightParen {
3735-
return Err(Diagnostic::error("Expect `)` to end group expression")
3739+
let mut exprs = vec![];
3740+
while !is_current_token(tokens, position, TokenKind::RightParen) {
3741+
exprs.push(parse_expression(context, env, tokens, position)?);
3742+
3743+
if !is_current_token(tokens, position, TokenKind::Comma) {
3744+
break;
3745+
}
3746+
3747+
// Consume `,`
3748+
*position += 1;
3749+
}
3750+
3751+
if exprs.is_empty() {
3752+
return Err(Diagnostic::error("Column or Row expression can't be empty")
37363753
.with_location(calculate_safe_location(tokens, *position))
3737-
.add_help("Try to add ')' at the end of group expression")
37383754
.as_boxed());
37393755
}
37403756

37413757
// Consume ')' token
3742-
*position += 1;
3758+
consume_token_or_error(
3759+
tokens,
3760+
position,
3761+
TokenKind::RightParen,
3762+
"Expect `(` at the end of column or row expression",
3763+
)?;
37433764

3744-
Ok(Box::new(GroupExpr { expr: expression }))
3765+
if exprs.len() == 1 {
3766+
let expr = exprs[0].clone();
3767+
Ok(Box::new(ColumnExpr { expr }))
3768+
} else {
3769+
let mut column_types = Vec::with_capacity(exprs.len());
3770+
for expr in exprs.iter() {
3771+
column_types.push(expr.expr_type());
3772+
}
3773+
let row_type = RowType::new(column_types);
3774+
Ok(Box::new(RowExpr { exprs, row_type }))
3775+
}
37453776
}
37463777

37473778
fn parse_case_expression(

0 commit comments

Comments
 (0)