all is working again

This commit is contained in:
Folkert 2021-03-13 22:36:44 +01:00
parent 022ed7b24c
commit c26fd45d54
6 changed files with 191 additions and 113 deletions

View File

@ -125,10 +125,11 @@ where
E: 'a,
{
move |_, state: State<'a>| {
if state.column > state.indent_col {
if state.column > min_indent {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, indent_problem(state.line, state.column), state))
//Ok((NoProgress, (), state))
}
}
}

View File

@ -366,6 +366,7 @@ fn parse_loc_term<'a>(
in_parens_region_fix(min_indent),
loc!(specialize(EExpr::Str, string_literal_help())),
loc!(specialize(EExpr::Number, number_literal_help())),
loc!(specialize(EExpr::Lambda, closure_help(min_indent))),
loc!(record_literal_help(min_indent)),
loc!(specialize(EExpr::List, list_literal_help(min_indent))),
loc!(ident_etc_help(min_indent))
@ -382,6 +383,7 @@ fn parse_loc_term_better<'a>(
in_parens_region_fix(min_indent),
loc!(specialize(EExpr::Str, string_literal_help())),
loc!(specialize(EExpr::Number, positive_number_literal_help())),
loc!(specialize(EExpr::Lambda, closure_help(min_indent))),
loc!(record_literal_help(min_indent)),
loc!(specialize(EExpr::List, list_literal_help(min_indent))),
// loc!(ident_etc_help(min_indent))
@ -579,7 +581,7 @@ fn foobar<'a>(
let initial = state;
let end = state.get_position();
match dbg!(space0_e(min_indent, EExpr::Space, EExpr::IndentEnd).parse(arena, state)) {
match space0_e(min_indent, EExpr::Space, EExpr::IndentEnd).parse(arena, state) {
Err((_, _, state)) => Ok((MadeProgress, expr.value, state)),
Ok((_, spaces_before_op, state)) => {
let expr_state = ExprState {
@ -605,6 +607,43 @@ struct ExprState<'a> {
end: Position,
}
// expr_state.expr = if spaces.is_empty() {
// expr_state.expr
// } else {
// arena
// .alloc(expr_state.expr.value)
// .with_spaces_after(spaces, expr_state.expr.region)
// };
// fn attach_spaces<'a>(&'a Bump, expr: &mut Located<Expr<'a>>, spaces: &'a [CommentOrNewline<'a>] ) {
//
//
//
// }
impl<'a> ExprState<'a> {
fn consume_spaces(&mut self, arena: &'a Bump) {
if !self.spaces_after.is_empty() {
if let Some(last) = self.arguments.pop() {
let new = last.value.with_spaces_after(self.spaces_after, last.region);
self.arguments.push(arena.alloc(new));
} else {
let region = self.expr.region;
let mut value = Expr::Num("");
std::mem::swap(&mut self.expr.value, &mut value);
self.expr = arena
.alloc(value)
.with_spaces_after(self.spaces_after, region);
};
self.spaces_after = &[];
}
}
}
fn parse_expr_final<'a>(
min_indent: u16,
expr_state: ExprState<'a>,
@ -631,7 +670,7 @@ fn to_call<'a>(
arena: &'a Bump,
arguments: Vec<'a, &'a Located<Expr<'a>>>,
loc_expr1: Located<Expr<'a>>,
_spaces_before: &'a [CommentOrNewline<'a>],
spaces_before: &'a [CommentOrNewline<'a>],
) -> Located<Expr<'a>> {
if arguments.is_empty() {
loc_expr1
@ -712,20 +751,9 @@ fn parse_expr_operator<'a>(
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
let (space_progress, mut spaces, state) =
let (_, spaces_after_operator, state) =
space0_e(min_indent, EExpr::Space, EExpr::IndentEnd).parse(arena, state)?;
// add previous spaces to the expr
std::mem::swap(&mut spaces, &mut expr_state.spaces_after);
expr_state.expr = if spaces.is_empty() {
expr_state.expr
} else {
arena
.alloc(expr_state.expr.value)
.with_spaces_after(spaces, expr_state.expr.region)
};
// a `-` is unary if it is preceded by a space and not followed by a space
let op = loc_op.value;
@ -761,16 +789,39 @@ fn parse_expr_operator<'a>(
parse_expr_end2(min_indent, expr_state, arena, state)
}
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 {
todo!()
}
}
BinOp::HasType => {
debug_assert!(expr_state.operators.is_empty());
dbg!(&expr_state.expr, &expr_state.arguments);
let expr_region = expr_state.expr.region;
match &expr_state.expr.value {
Expr::GlobalTag(name) => {
let indented_more = min_indent + 1;
let region = expr_state.expr.region;
let (_, ann_type, state) = specialize(
EExpr::Type,
space0_before_e(
@ -820,31 +871,86 @@ fn parse_expr_operator<'a>(
state,
));
}
_ => panic!(),
_ => {
expr_state.consume_spaces(arena);
let call = to_call(
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) {
Ok(good) => {
let indented_more = min_indent + 1;
let (_, ann_type, state) = specialize(
EExpr::Type,
space0_before_e(
type_annotation::located_help(indented_more),
min_indent,
Type::TSpace,
Type::TIndentStart,
),
)
.parse(arena, state)?;
let alias_region = Region::span_across(&expr_region, &ann_type.region);
let alias = Def::Annotation(Located::at(expr_region, good), ann_type);
let loc_def = &*arena.alloc(Located::at(alias_region, alias));
let foo = space0_before_e(
move |a, s| parse_expr_help(min_indent, a, s),
min_indent,
EExpr::Space,
EExpr::IndentEnd,
);
let (_, loc_ret, state) = foo.parse(arena, state)?;
return Ok((
MadeProgress,
Expr::Defs(&*arena.alloc([loc_def]), arena.alloc(loc_ret)),
state,
));
}
Err(_) => {
// 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))
}
}
}
}
}
_ => match loc_possibly_negative_or_negated_term(min_indent).parse(arena, state) {
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
Ok((_, new_expr, state)) => {
Ok((_, mut new_expr, state)) => {
let new_end = state.get_position();
expr_state.initial = state;
// put the spaces from after the operator in front of the new_expr
if !spaces_after_operator.is_empty() {
new_expr = arena
.alloc(new_expr.value)
.with_spaces_before(spaces_after_operator, new_expr.region);
}
match space0_e(min_indent, EExpr::Space, EExpr::IndentEnd).parse(arena, state) {
Err((_, _, state)) => {
let spaces = expr_state.spaces_after;
let new_expr = if spaces.is_empty() {
new_expr
} else {
arena
.alloc(new_expr.value)
.with_spaces_before(spaces, new_expr.region)
};
let args = std::mem::replace(&mut expr_state.arguments, Vec::new_in(arena));
let call = to_call(arena, args, expr_state.expr, spaces);
let call = to_call(arena, args, expr_state.expr, &[]);
expr_state.operators.push((call, loc_op));
expr_state.expr = new_expr;
@ -853,17 +959,7 @@ fn parse_expr_operator<'a>(
parse_expr_final(min_indent, expr_state, arena, state)
}
Ok((_, mut spaces, state)) => {
std::mem::swap(&mut spaces, &mut expr_state.spaces_after);
let new_expr = if spaces.is_empty() {
new_expr
} else {
arena
.alloc(new_expr.value)
.with_spaces_before(spaces, new_expr.region)
};
Ok((_, spaces, state)) => {
let args = std::mem::replace(&mut expr_state.arguments, Vec::new_in(arena));
let call = to_call(arena, args, expr_state.expr, spaces);
@ -871,6 +967,7 @@ fn parse_expr_operator<'a>(
expr_state.operators.push((call, loc_op));
expr_state.expr = new_expr;
expr_state.end = new_end;
expr_state.spaces_after = spaces;
parse_expr_end(min_indent, expr_state, arena, state)
}
@ -896,42 +993,31 @@ fn parse_expr_end2<'a>(
match parser.parse(arena, state) {
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
Ok((_, arg, state)) => {
Ok((_, mut arg, state)) => {
let new_end = state.get_position();
// now that we have `function arg1 ... <spaces> argn`, attach the spaces to the `argn`
if !expr_state.spaces_after.is_empty() {
arg = arena
.alloc(arg.value)
.with_spaces_before(expr_state.spaces_after, arg.region);
expr_state.spaces_after = &[];
}
expr_state.initial = state;
match space0_e(min_indent, EExpr::Space, EExpr::IndentEnd).parse(arena, state) {
Err((_, _, state)) => {
let spaces = expr_state.spaces_after;
let arg = if spaces.is_empty() {
arg
} else {
arena
.alloc(arg.value)
.with_spaces_before(spaces, arg.region)
};
expr_state.arguments.push(arena.alloc(arg));
expr_state.end = new_end;
expr_state.spaces_after = &[];
parse_expr_final(min_indent, expr_state, arena, state)
}
Ok((_, mut spaces, state)) => {
std::mem::swap(&mut spaces, &mut expr_state.spaces_after);
let arg = if spaces.is_empty() {
arg
} else {
arena
.alloc(arg.value)
.with_spaces_before(spaces, arg.region)
};
Ok((_, new_spaces, state)) => {
expr_state.arguments.push(arena.alloc(arg));
expr_state.end = new_end;
expr_state.spaces_after = new_spaces;
parse_expr_end(min_indent, expr_state, arena, state)
}
@ -943,6 +1029,7 @@ fn parse_expr_end2<'a>(
match loc!(operator()).parse(arena, state) {
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
Ok((_, loc_op, state)) => {
expr_state.consume_spaces(arena);
expr_state.initial = before_op;
parse_expr_operator(min_indent, expr_state, loc_op, arena, state)
}
@ -988,41 +1075,6 @@ fn parse_expr_end<'a>(
state: State<'a>,
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
return parse_expr_end2(min_indent, expr_state, arena, state);
let parser = and!(
loc!(operator()),
// The spaces *after* the operator can be attached directly to
// the expression following the operator.
space0_before_e(
move |arena, state| parse_expr_help(min_indent, arena, state),
min_indent,
EExpr::Space,
EExpr::IndentEnd,
)
);
match parser.parse(arena, state) {
Ok((_, (loc_op, loc_expr2), state)) => {
let ExprState {
expr: loc_expr1,
spaces_after: spaces_before,
..
} = expr_state;
let loc_expr1 = if spaces_before.is_empty() {
loc_expr1
} else {
// Attach the spaces retroactively to the expression preceding the operator.
arena
.alloc(loc_expr1.value)
.with_spaces_after(spaces_before, loc_expr1.region)
};
let tuple = arena.alloc((loc_expr1, loc_op, loc_expr2));
Ok((MadeProgress, Expr::BinOp(tuple), state))
}
Err((NoProgress, _, _)) => Ok((MadeProgress, expr_state.expr.value, expr_state.initial)),
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
}
}
fn parse_expr_help<'a>(

View File

@ -254,7 +254,12 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
if state.has_reached_end() {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, SyntaxError::ConditionFailed, state))
dbg!(state);
Err((
NoProgress,
SyntaxError::NotEndOfFile(state.line, state.column),
state,
))
}
}
}

View File

@ -191,6 +191,7 @@ pub enum SyntaxError<'a> {
Expr(EExpr<'a>),
Header(EHeader<'a>),
Space(BadInputError),
NotEndOfFile(Row, Col),
}
#[derive(Debug, Clone, PartialEq, Eq)]

View File

@ -125,6 +125,22 @@ fn to_syntax_report<'a>(
report(doc)
}
NotEndOfFile(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col);
let doc = alloc.stack(vec![
alloc.reflow(r"I expected to reach the end of the file, but got stuck here:"),
alloc.region_with_subregion(surroundings, region),
alloc.concat(vec![alloc.reflow("no hints")]),
]);
Report {
filename,
doc,
title: "NOT END OF FILE".to_string(),
}
}
SyntaxError::Eof(region) => {
let doc = alloc.stack(vec![alloc.reflow("End of Field"), alloc.region(*region)]);

View File

@ -65,6 +65,7 @@ mod test_reporting {
problems: can_problems,
..
} = can_expr(arena, expr_src)?;
dbg!(&loc_expr);
let mut subs = Subs::new(var_store.into());
for (var, name) in output.introduced_variables.name_by_var {
@ -4205,12 +4206,12 @@ mod test_reporting {
indoc!(
r#"
TOO MANY ARGS
The `add` function expects 2 arguments, but it got 3 instead:
4 Num.add 1 2
^^^^^^^
This value is not a function, but it was given 3 arguments:
3 x == 5
^
Are there any missing commas? Or missing parentheses?
"#
),
@ -5727,22 +5728,24 @@ mod test_reporting {
indoc!(
r#"
main =
5 : I64
(\x -> x) : I64
3
"#
),
indoc!(
r#"
UNKNOWN OPERATOR
This looks like an operator, but it's not one I recognize!
1 main =
2 5 : I64
^
2 (\x -> x) : I64
^
The has-type operator : can only occur in a definition's type
signature, like
increment : I64 -> I64
increment = \x -> x + 1
"#