mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Fix annotated defs in repl
This commit is contained in:
parent
daa87093ca
commit
0c8f6a0a72
3 changed files with 117 additions and 20 deletions
|
@ -925,6 +925,8 @@ pub fn parse_single_def<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
// This is a macro only because trying to make it be a function caused lifetime issues.
|
||||
#[macro_export]
|
||||
macro_rules! join_ann_to_body {
|
||||
($arena:expr, $loc_pattern:expr, $loc_def_expr:expr, $ann_pattern:expr, $ann_type:expr, $spaces_before_current:expr, $region:expr) => {{
|
||||
// join this body with the preceding annotation
|
||||
|
@ -934,20 +936,24 @@ macro_rules! join_ann_to_body {
|
|||
ann_type: $arena.alloc(*$ann_type),
|
||||
comment: $spaces_before_current
|
||||
.first()
|
||||
.and_then(CommentOrNewline::comment_str),
|
||||
.and_then($crate::ast::CommentOrNewline::comment_str),
|
||||
body_pattern: $arena.alloc($loc_pattern),
|
||||
body_expr: *$arena.alloc($loc_def_expr),
|
||||
};
|
||||
|
||||
(
|
||||
value_def,
|
||||
Region::span_across(&$ann_pattern.region, &$region),
|
||||
roc_region::all::Region::span_across(&$ann_pattern.region, &$region),
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
// This is a macro only because trying to make it be a function caused lifetime issues.
|
||||
#[macro_export]
|
||||
macro_rules! join_alias_to_body {
|
||||
($arena:expr, $loc_pattern:expr, $loc_def_expr:expr, $header:expr, $ann_type:expr, $spaces_before_current:expr, $region:expr) => {{
|
||||
use roc_region::all::Region;
|
||||
|
||||
// This is a case like
|
||||
// UserId x : [UserId Int]
|
||||
// UserId x = UserId 42
|
||||
|
@ -966,7 +972,7 @@ macro_rules! join_alias_to_body {
|
|||
ann_type: $arena.alloc(*$ann_type),
|
||||
comment: $spaces_before_current
|
||||
.first()
|
||||
.and_then(CommentOrNewline::comment_str),
|
||||
.and_then($crate::ast::CommentOrNewline::comment_str),
|
||||
body_pattern: $arena.alloc($loc_pattern),
|
||||
body_expr: *$arena.alloc($loc_def_expr),
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ use roc_parse::expr::{parse_single_def, ExprParseOptions, SingleDef};
|
|||
use roc_parse::parser::Either;
|
||||
use roc_parse::parser::{EClosure, EExpr};
|
||||
use roc_parse::state::State;
|
||||
use roc_parse::{join_alias_to_body, join_ann_to_body};
|
||||
use roc_region::all::Loc;
|
||||
use roc_repl_eval::gen::{Problems, ReplOutput};
|
||||
use rustyline::highlight::{Highlighter, PromptInfo};
|
||||
|
@ -124,18 +125,8 @@ impl ReplState {
|
|||
},
|
||||
_,
|
||||
) => {
|
||||
// We received a type annotation, like `x : Str`
|
||||
//
|
||||
// This might be the beginning of an AnnotatedBody, or it might be
|
||||
// a standalone annotation.
|
||||
//
|
||||
// If the input ends in a newline, that means the user pressed Enter
|
||||
// twice after the annotation, indicating this is not an AnnotatedBody,
|
||||
// but rather a standalone Annotation. As such, record it as a PastDef!
|
||||
if src.ends_with('\n') {
|
||||
// Record the standalone type annotation for future use
|
||||
self.add_past_def(ident.trim_end().to_string(), src.to_string());
|
||||
}
|
||||
// Record the standalone type annotation for future use.
|
||||
self.add_past_def(ident.trim_end().to_string(), src.to_string());
|
||||
|
||||
// Return early without running eval, since neither standalone annotations
|
||||
// nor pending potential AnnotatedBody exprs can be evaluated as expressions.
|
||||
|
@ -290,6 +281,110 @@ fn parse_src<'a>(arena: &'a Bump, line: &'a str) -> ParseOutcome<'a> {
|
|||
&arena,
|
||||
State::new(src_bytes),
|
||||
) {
|
||||
Ok((
|
||||
_,
|
||||
Some(SingleDef {
|
||||
type_or_value: Either::First(TypeDef::Alias { header, ann }),
|
||||
..
|
||||
}),
|
||||
state,
|
||||
)) => {
|
||||
// This *could* be an AnnotatedBody, e.g. in a case like this:
|
||||
//
|
||||
// UserId x : [UserId Int]
|
||||
// UserId x = UserId 42
|
||||
//
|
||||
// We optimistically parsed the first line as an alias; we might now
|
||||
// turn it into an annotation.
|
||||
match parse_single_def(
|
||||
ExprParseOptions {
|
||||
accept_multi_backpassing: true,
|
||||
check_for_arrow: true,
|
||||
},
|
||||
0,
|
||||
&arena,
|
||||
state,
|
||||
) {
|
||||
Ok((
|
||||
_,
|
||||
Some(SingleDef {
|
||||
type_or_value:
|
||||
Either::Second(ValueDef::Body(loc_pattern, loc_def_expr)),
|
||||
region,
|
||||
spaces_before,
|
||||
}),
|
||||
_,
|
||||
)) if spaces_before.len() <= 1 => {
|
||||
// This was, in fact, an AnnotatedBody! Build and return it.
|
||||
let (value_def, _) = join_alias_to_body!(
|
||||
arena,
|
||||
loc_pattern,
|
||||
loc_def_expr,
|
||||
header,
|
||||
&ann,
|
||||
spaces_before,
|
||||
region
|
||||
);
|
||||
|
||||
ParseOutcome::ValueDef(value_def)
|
||||
}
|
||||
_ => {
|
||||
// This was not an AnnotatedBody, so return the alias.
|
||||
ParseOutcome::TypeDef(TypeDef::Alias { header, ann })
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((
|
||||
_,
|
||||
Some(SingleDef {
|
||||
type_or_value:
|
||||
Either::Second(ValueDef::Annotation(ann_pattern, ann_type)),
|
||||
..
|
||||
}),
|
||||
state,
|
||||
)) => {
|
||||
// This *could* be an AnnotatedBody, if the next line is a body.
|
||||
match parse_single_def(
|
||||
ExprParseOptions {
|
||||
accept_multi_backpassing: true,
|
||||
check_for_arrow: true,
|
||||
},
|
||||
0,
|
||||
&arena,
|
||||
state,
|
||||
) {
|
||||
Ok((
|
||||
_,
|
||||
Some(SingleDef {
|
||||
type_or_value:
|
||||
Either::Second(ValueDef::Body(loc_pattern, loc_def_expr)),
|
||||
region,
|
||||
spaces_before,
|
||||
}),
|
||||
_,
|
||||
)) if spaces_before.len() <= 1 => {
|
||||
// This was, in fact, an AnnotatedBody! Build and return it.
|
||||
let (value_def, _) = join_ann_to_body!(
|
||||
arena,
|
||||
loc_pattern,
|
||||
loc_def_expr,
|
||||
&ann_pattern,
|
||||
&ann_type,
|
||||
spaces_before,
|
||||
region
|
||||
);
|
||||
|
||||
ParseOutcome::ValueDef(value_def)
|
||||
}
|
||||
_ => {
|
||||
// This was not an AnnotatedBody, so return the standalone annotation.
|
||||
ParseOutcome::ValueDef(ValueDef::Annotation(
|
||||
ann_pattern,
|
||||
ann_type,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((
|
||||
_,
|
||||
Some(SingleDef {
|
||||
|
|
|
@ -38,11 +38,7 @@ fn annotated_body() {
|
|||
|
||||
input.push_str("t = A");
|
||||
|
||||
incomplete(&mut input);
|
||||
|
||||
let mut state = ReplState::new();
|
||||
|
||||
complete(&input, &mut state, Ok(("A : [A]*", "t")));
|
||||
complete(&input, &mut ReplState::new(), Ok(("A : [A, B, C]", "t")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue