This commit is contained in:
Folkert 2021-03-15 23:51:06 +01:00
parent ecc689e84b
commit 5adeedba9d
2 changed files with 172 additions and 176 deletions

View file

@ -494,6 +494,62 @@ impl<'a> ExprState<'a> {
self.spaces_after = &[]; self.spaces_after = &[];
} }
} }
fn validate_assignment_or_backpassing<F>(
mut self,
arena: &'a Bump,
loc_op: Located<BinOp>,
argument_error: F,
) -> Result<Located<Expr<'a>>, EExpr<'a>>
where
F: Fn(Region, Row, Col) -> EExpr<'a>,
{
if !self.operators.is_empty() {
// this `=` or `:` likely occured inline; treat it as an invalid operator
let opchar = match loc_op.value {
BinOp::Assignment => arena.alloc([b'=']) as &[_],
BinOp::Backpassing => arena.alloc([b'<', b'-']) as &[_],
_ => unreachable!(),
};
let fail =
EExpr::BadOperator(opchar, loc_op.region.start_line, loc_op.region.start_col);
Err(fail)
} else if !self.arguments.is_empty() {
let region = Region::across_all(self.arguments.iter().map(|v| &v.region));
Err(argument_error(
region,
loc_op.region.start_line,
loc_op.region.start_col,
))
} else {
self.consume_spaces(arena);
Ok(to_call(arena, self.arguments, self.expr, &[]))
}
}
fn validate_has_type(
mut self,
arena: &'a Bump,
loc_op: Located<BinOp>,
) -> Result<(Located<Expr<'a>>, Vec<'a, &'a Located<Expr<'a>>>), EExpr<'a>> {
debug_assert_eq!(loc_op.value, BinOp::HasType);
if !self.operators.is_empty() || !self.arguments.is_empty() {
// this `:`; treat it as an invalid operator
let opchar = arena.alloc([b':']) as &[_];
let fail =
EExpr::BadOperator(opchar, loc_op.region.start_line, loc_op.region.start_col);
Err(fail)
} else {
self.consume_spaces(arena);
Ok((self.expr, self.arguments))
}
}
} }
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
@ -883,7 +939,7 @@ fn parse_defs_end<'a>(
parse_defs_end(start, def_state, arena, state) parse_defs_end(start, def_state, arena, state)
} }
_ => { _ => {
// this is no def, because there is no `=`, `:` or `<-`; parse as an expr // this is no def, because there is no `=` or `:`; parse as an expr
let state = initial; let state = initial;
let parse_final_expr = space0_before_e( let parse_final_expr = space0_before_e(
move |a, s| parse_expr_help(min_indent, a, s), move |a, s| parse_expr_help(min_indent, a, s),
@ -952,37 +1008,12 @@ fn parse_expr_operator<'a>(
parse_expr_end(min_indent, start, expr_state, arena, state) parse_expr_end(min_indent, start, expr_state, arena, state)
} }
BinOp::Assignment => { BinOp::Assignment => {
if !expr_state.operators.is_empty() {
// this `=` likely occured inline; treat it as an invalid operator
let fail = EExpr::BadOperator(
arena.alloc([b'=']),
loc_op.region.start_line,
loc_op.region.start_col,
);
Err((MadeProgress, fail, state))
} else if !expr_state.arguments.is_empty() {
let region = Region::across_all(expr_state.arguments.iter().map(|v| &v.region));
let fail = EExpr::ElmStyleFunction(
region,
loc_op.region.start_line,
loc_op.region.start_col,
);
Err((MadeProgress, fail, state))
} else {
expr_state.consume_spaces(arena);
let expr_region = expr_state.expr.region; let expr_region = expr_state.expr.region;
let indented_more = start.col + 1; let indented_more = start.col + 1;
let call = to_call( let call = expr_state
arena, .validate_assignment_or_backpassing(arena, loc_op, EExpr::ElmStyleFunction)
expr_state.arguments, .map_err(|fail| (MadeProgress, fail, state))?;
expr_state.expr,
spaces_after_operator,
);
let (loc_def, state) = { let (loc_def, state) = {
match expr_to_pattern_help(arena, &call.value) { match expr_to_pattern_help(arena, &call.value) {
@ -1026,39 +1057,15 @@ fn parse_expr_operator<'a>(
parse_defs_end(start, def_state, arena, state) parse_defs_end(start, def_state, arena, state)
} }
}
BinOp::Backpassing => { BinOp::Backpassing => {
if !expr_state.operators.is_empty() {
// this `=` likely occured inline; treat it as an invalid operator
let fail = EExpr::BadOperator(
arena.alloc([b'<', b'-']),
loc_op.region.start_line,
loc_op.region.start_col,
);
Err((MadeProgress, fail, state))
} else if !expr_state.arguments.is_empty() {
let region = Region::across_all(expr_state.arguments.iter().map(|v| &v.region));
let fail = EExpr::ElmStyleFunction(
region,
loc_op.region.start_line,
loc_op.region.start_col,
);
Err((MadeProgress, fail, state))
} else {
expr_state.consume_spaces(arena);
let expr_region = expr_state.expr.region; let expr_region = expr_state.expr.region;
let indented_more = start.col + 1; let indented_more = start.col + 1;
let call = to_call( let call = expr_state
arena, .validate_assignment_or_backpassing(arena, loc_op, |_, r, c| {
expr_state.arguments, EExpr::BadOperator(&[b'<', b'-'], r, c)
expr_state.expr, })
spaces_after_operator, .map_err(|fail| (MadeProgress, fail, state))?;
);
let (loc_pattern, loc_body, state) = { let (loc_pattern, loc_body, state) = {
match expr_to_pattern_help(arena, &call.value) { match expr_to_pattern_help(arena, &call.value) {
@ -1105,22 +1112,19 @@ fn parse_expr_operator<'a>(
Ok((MadeProgress, ret, state)) Ok((MadeProgress, ret, state))
} }
}
BinOp::HasType => { BinOp::HasType => {
debug_assert!(expr_state.operators.is_empty());
let expr_region = expr_state.expr.region; let expr_region = expr_state.expr.region;
let indented_more = start.col + 1; let indented_more = start.col + 1;
expr_state.consume_spaces(arena); let (expr, arguments) = expr_state
.validate_has_type(arena, loc_op)
.map_err(|fail| (MadeProgress, fail, state))?;
let (loc_def, state) = match &expr_state.expr.value { let (loc_def, state) = match &expr.value {
Expr::GlobalTag(name) => { Expr::GlobalTag(name) => {
let mut type_arguments = let mut type_arguments = Vec::with_capacity_in(arguments.len(), arena);
Vec::with_capacity_in(expr_state.arguments.len(), arena);
for argument in expr_state.arguments { for argument in arguments {
match expr_to_pattern_help(arena, &argument.value) { match expr_to_pattern_help(arena, &argument.value) {
Ok(good) => { Ok(good) => {
type_arguments.push(Located::at(argument.region, good)); type_arguments.push(Located::at(argument.region, good));
@ -1140,11 +1144,10 @@ fn parse_expr_operator<'a>(
) )
.parse(arena, state)?; .parse(arena, state)?;
let alias_region = let alias_region = Region::span_across(&expr.region, &ann_type.region);
Region::span_across(&expr_state.expr.region, &ann_type.region);
let alias = Def::Alias { let alias = Def::Alias {
name: Located::at(expr_state.expr.region, name), name: Located::at(expr.region, name),
vars: type_arguments.into_bump_slice(), vars: type_arguments.into_bump_slice(),
ann: ann_type, ann: ann_type,
}; };
@ -1153,14 +1156,7 @@ fn parse_expr_operator<'a>(
} }
_ => { _ => {
let call = to_call( let call = to_call(arena, arguments, expr, spaces_after_operator);
arena,
expr_state.arguments,
expr_state.expr,
spaces_after_operator,
);
// let aligned_like_a_def = expr_state.expr.region.start_col == state.indent_col;
match expr_to_pattern_help(arena, &call.value) { match expr_to_pattern_help(arena, &call.value) {
Ok(good) => { Ok(good) => {

View file

@ -152,7 +152,7 @@ pub struct Position {
pub col: u16, pub col: u16,
} }
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(Clone, Eq, Copy, PartialEq, PartialOrd, Ord, Hash)]
pub struct Located<T> { pub struct Located<T> {
pub region: Region, pub region: Region,
pub value: T, pub value: T,