use crate::input::proto::substrait;
use crate::output::diagnostic;
use crate::output::type_system::data;
use crate::parse::context;
use crate::parse::expressions;
use crate::parse::expressions::literals;
use crate::parse::types;
use std::sync::Arc;
pub fn parse_if_then(
x: &substrait::expression::IfThen,
y: &mut context::Context,
) -> diagnostic::Result<expressions::Expression> {
let mut return_type: data::Type = Arc::default();
let mut args = vec![];
proto_required_repeated_field!(x, y, ifs, |x, y| {
let (n, e) = proto_required_field!(x, y, r#if, expressions::parse_predicate);
let condition = e.unwrap_or_default();
let condition_type = n.data_type();
let (n, e) = proto_required_field!(x, y, then, expressions::parse_expression);
let value = e.unwrap_or_default();
let value_type = n.data_type();
return_type = types::promote_and_assert_equal(
y,
&value_type,
&return_type,
"branches must yield the same type",
);
if !condition_type.is_unresolved() && condition_type.nullable() {
return_type = return_type.make_nullable();
}
describe!(y, Misc, "If {} yield {}", &condition, &value);
args.push(expressions::functions::FunctionArgument::Value(
condition_type,
condition,
));
args.push(expressions::functions::FunctionArgument::Value(
value_type, value,
));
Ok(())
});
if x.r#else.is_some() {
let (n, e) = proto_boxed_required_field!(x, y, r#else, expressions::parse_expression);
let value = e.unwrap_or_default();
let value_type = n.data_type();
return_type = types::promote_and_assert_equal(
y,
&n.data_type(),
&return_type,
"branches must yield the same type",
);
args.push(expressions::functions::FunctionArgument::Value(
value_type, value,
));
} else {
comment!(y, "Otherwise, yield null.");
return_type = return_type.make_nullable();
args.push(expressions::functions::FunctionArgument::Value(
return_type.clone(),
expressions::Expression::new_null(return_type.clone()),
));
}
y.set_data_type(return_type);
summary!(
y,
"Selects the value corresponding to the first condition that yields \
true. If none of the conditions yield true, return {}.",
args.last().unwrap()
);
let expression = expressions::Expression::Function(String::from("if_then"), args);
describe!(y, Expression, "{}", expression);
Ok(expression)
}
pub fn parse_switch(
x: &substrait::expression::SwitchExpression,
y: &mut context::Context,
) -> diagnostic::Result<expressions::Expression> {
let mut return_type: data::Type = Arc::default();
let mut args = vec![];
let (n, e) = proto_boxed_required_field!(x, y, r#match, expressions::parse_expression);
let mut match_type = n.data_type();
args.push(expressions::functions::FunctionArgument::Value(
match_type.clone(),
e.unwrap_or_default(),
));
proto_required_repeated_field!(x, y, ifs, |x, y| {
let (n, e) = proto_required_field!(x, y, r#if, literals::parse_literal);
let match_value = e.unwrap_or_default();
let match_field_type = n.data_type();
match_type = types::promote_and_assert_equal(
y,
&n.data_type(),
&match_type,
"literal type must match switch expression",
);
let (n, e) = proto_required_field!(x, y, then, expressions::parse_expression);
let value = e.unwrap_or_default();
let value_type = n.data_type();
return_type = types::promote_and_assert_equal(
y,
&n.data_type(),
&return_type,
"branches must yield the same type",
);
describe!(y, Misc, "If match == {} yield {}", &match_value, &value);
args.push(expressions::functions::FunctionArgument::Value(
match_field_type,
expressions::Expression::from(match_value),
));
args.push(expressions::functions::FunctionArgument::Value(
value_type, value,
));
Ok(())
});
if x.r#else.is_some() {
let (n, e) = proto_boxed_required_field!(x, y, r#else, expressions::parse_expression);
let value = e.unwrap_or_default();
let value_type = n.data_type();
return_type = types::promote_and_assert_equal(
y,
&n.data_type(),
&return_type,
"branches must yield the same type",
);
args.push(expressions::functions::FunctionArgument::Value(
value_type, value,
));
} else {
comment!(y, "Otherwise, yield null.");
return_type = return_type.make_nullable();
args.push(expressions::functions::FunctionArgument::Value(
return_type.clone(),
expressions::Expression::new_null(return_type.clone()),
));
}
y.set_data_type(return_type);
summary!(
y,
"Selects the value corresponding to the switch case that matches {}. \
If none of the cases match, return {}.",
args.first().unwrap(),
args.last().unwrap()
);
let expression = expressions::Expression::Function(String::from("switch"), args);
describe!(y, Expression, "{}", expression);
Ok(expression)
}
pub fn parse_singular_or_list(
x: &substrait::expression::SingularOrList,
y: &mut context::Context,
) -> diagnostic::Result<expressions::Expression> {
let mut args = vec![];
let (n, e) = proto_boxed_required_field!(x, y, value, expressions::parse_expression);
let match_type = n.data_type();
args.push(expressions::functions::FunctionArgument::Value(
match_type.clone(),
e.unwrap_or_default(),
));
proto_required_repeated_field!(x, y, options, |x, y| {
let expression = expressions::parse_expression(x, y)?;
let value_type = y.data_type();
args.push(expressions::functions::FunctionArgument::Value(
value_type.clone(),
expression,
));
types::assert_equal(
y,
&value_type,
&match_type,
"option type must match value type",
);
Ok(())
});
y.set_data_type(data::new_predicate());
summary!(
y,
"Returns true if and only if {} is equal to any of the options.",
args.first().unwrap()
);
let expression = expressions::Expression::Function(String::from("match"), args);
describe!(y, Expression, "{}", expression);
Ok(expression)
}
pub fn parse_multi_or_list(
x: &substrait::expression::MultiOrList,
y: &mut context::Context,
) -> diagnostic::Result<expressions::Expression> {
let mut args = vec![];
let (ns, es) = proto_required_repeated_field!(x, y, value, expressions::parse_expression);
let match_types = ns.iter().map(|x| x.data_type()).collect::<Vec<_>>();
args.push(expressions::functions::FunctionArgument::Value(
data::new_unresolved_type(),
expressions::Expression::Tuple(es.into_iter().map(|x| x.unwrap_or_default()).collect()),
));
proto_required_repeated_field!(x, y, options, |x, y| {
let (ns, es) = proto_required_repeated_field!(x, y, fields, expressions::parse_expression);
let value_types = ns.iter().map(|x| x.data_type()).collect::<Vec<_>>();
args.push(expressions::functions::FunctionArgument::Value(
data::new_unresolved_type(),
expressions::Expression::Tuple(es.into_iter().map(|x| x.unwrap_or_default()).collect()),
));
if match_types.len() != value_types.len() {
diagnostic!(
y,
Error,
TypeMismatch,
"option types must match value types: numbers of fields differ"
)
}
for (index, (value_type, match_type)) in
value_types.iter().zip(match_types.iter()).enumerate()
{
types::assert_equal(
y,
value_type,
match_type,
format!("option type must match value type for field {index}"),
);
}
Ok(())
});
y.set_data_type(data::new_predicate());
summary!(
y,
"Returns true if and only if {} is equal to any of the options.",
args.first().unwrap()
);
let expression = expressions::Expression::Function(String::from("match"), args);
describe!(y, Expression, "{}", expression);
Ok(expression)
}