use crate::{
error::{err, ok},
CallPath, CompileError, CompileResult, DelayedEnumVariantResolution, DelayedResolutionVariant,
DelayedStructFieldResolution, DelayedTupleVariantResolution, Expression, Ident, Literal,
Scrutinee, StructScrutineeField,
};
use sway_types::span::Span;
pub type MatchReqMap = Vec<(Expression, Expression)>;
pub type MatchImplMap = Vec<(Ident, Expression)>;
pub type MatcherResult = Option<(MatchReqMap, MatchImplMap)>;
pub fn matcher(exp: &Expression, scrutinee: &Scrutinee) -> CompileResult<MatcherResult> {
let mut errors = vec![];
let warnings = vec![];
match scrutinee {
Scrutinee::Literal { value, span } => match_literal(exp, value, span),
Scrutinee::Variable { name, span } => match_variable(exp, name, span),
Scrutinee::StructScrutinee {
struct_name,
fields,
span,
} => match_struct(exp, struct_name, fields, span),
Scrutinee::EnumScrutinee {
call_path,
args,
span,
} => match_enum(exp, call_path, args, span),
Scrutinee::Tuple { elems, span } => match_tuple(exp, elems, span),
scrutinee => {
eprintln!("Unimplemented scrutinee: {:?}", scrutinee,);
errors.push(CompileError::Unimplemented(
"this match expression scrutinee is not implemented",
scrutinee.span(),
));
ok(Some((vec![], vec![])), warnings, errors)
}
}
}
fn match_literal(
exp: &Expression,
scrutinee: &Literal,
scrutinee_span: &Span,
) -> CompileResult<MatcherResult> {
let match_req_map = vec![(
exp.to_owned(),
Expression::Literal {
value: scrutinee.clone(),
span: scrutinee_span.clone(),
},
)];
let match_impl_map = vec![];
ok(Some((match_req_map, match_impl_map)), vec![], vec![])
}
fn match_variable(
exp: &Expression,
scrutinee_name: &Ident,
_span: &Span,
) -> CompileResult<MatcherResult> {
let match_req_map = vec![];
let match_impl_map = vec![(scrutinee_name.to_owned(), exp.to_owned())];
ok(Some((match_req_map, match_impl_map)), vec![], vec![])
}
fn match_struct(
exp: &Expression,
struct_name: &Ident,
fields: &[StructScrutineeField],
span: &Span,
) -> CompileResult<MatcherResult> {
let mut warnings = vec![];
let mut errors = vec![];
let mut match_req_map = vec![];
let mut match_impl_map = vec![];
for field in fields.iter() {
let field_name = field.field.clone();
let scrutinee = field.scrutinee.clone();
let delayed_resolution_exp = Expression::DelayedMatchTypeResolution {
variant: DelayedResolutionVariant::StructField(DelayedStructFieldResolution {
exp: Box::new(exp.clone()),
struct_name: struct_name.to_owned(),
field: field_name.clone(),
}),
span: span.clone(),
};
match scrutinee {
None => {
match_impl_map.push((field_name.clone(), delayed_resolution_exp));
}
Some(scrutinee) => {
let new_matches = check!(
matcher(&delayed_resolution_exp, &scrutinee),
return err(warnings, errors),
warnings,
errors
);
match new_matches {
Some((mut new_match_req_map, mut new_match_impl_map)) => {
match_req_map.append(&mut new_match_req_map);
match_impl_map.append(&mut new_match_impl_map);
}
None => return ok(None, warnings, errors),
}
}
}
}
ok(Some((match_req_map, match_impl_map)), warnings, errors)
}
fn match_enum(
exp: &Expression,
call_path: &CallPath,
args: &[Scrutinee],
span: &Span,
) -> CompileResult<MatcherResult> {
let mut warnings = vec![];
let mut errors = vec![];
let mut match_req_map = vec![];
let mut match_impl_map = vec![];
for (pos, arg) in args.iter().enumerate() {
let delayed_resolution_exp = Expression::DelayedMatchTypeResolution {
variant: DelayedResolutionVariant::EnumVariant(DelayedEnumVariantResolution {
exp: Box::new(exp.clone()),
call_path: call_path.to_owned(),
arg_num: pos,
}),
span: span.clone(),
};
let new_matches = check!(
matcher(&delayed_resolution_exp, arg),
return err(warnings, errors),
warnings,
errors
);
match new_matches {
Some((mut new_match_req_map, mut new_match_impl_map)) => {
match_req_map.append(&mut new_match_req_map);
match_impl_map.append(&mut new_match_impl_map);
}
None => return ok(None, warnings, errors),
}
}
ok(Some((match_req_map, match_impl_map)), warnings, errors)
}
fn match_tuple(exp: &Expression, elems: &[Scrutinee], span: &Span) -> CompileResult<MatcherResult> {
let mut warnings = vec![];
let mut errors = vec![];
let mut match_req_map = vec![];
let mut match_impl_map = vec![];
for (pos, elem) in elems.iter().enumerate() {
let delayed_resolution_exp = Expression::DelayedMatchTypeResolution {
variant: DelayedResolutionVariant::TupleVariant(DelayedTupleVariantResolution {
exp: Box::new(exp.clone()),
elem_num: pos,
}),
span: span.clone(),
};
let new_matches = check!(
matcher(&delayed_resolution_exp, elem),
return err(warnings, errors),
warnings,
errors
);
match new_matches {
Some((mut new_match_req_map, mut new_match_impl_map)) => {
match_req_map.append(&mut new_match_req_map);
match_impl_map.append(&mut new_match_impl_map);
}
None => return ok(None, warnings, errors),
}
}
ok(Some((match_req_map, match_impl_map)), warnings, errors)
}