mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
Parse !
suffixes as an Expr::TaskAwaitBang instead of using suffix field in ident
This commit is contained in:
parent
4b4aee3c1a
commit
6080c12ca8
8 changed files with 94 additions and 89 deletions
|
@ -342,6 +342,7 @@ pub fn desugar_expr<'a>(
|
|||
|
||||
arena.alloc(Loc { region, value })
|
||||
}
|
||||
TaskAwaitBang(_) => todo!("desugar task await bang"),
|
||||
RecordAccess(sub_expr, paths) => {
|
||||
let region = loc_expr.region;
|
||||
let loc_sub_expr = Loc {
|
||||
|
|
|
@ -1171,6 +1171,7 @@ pub fn canonicalize_expr<'a>(
|
|||
output,
|
||||
)
|
||||
}
|
||||
ast::Expr::TaskAwaitBang(..) => todo!("canonicalize_expr on TaskAwaitBang"),
|
||||
ast::Expr::Tag(tag) => {
|
||||
let variant_var = var_store.fresh();
|
||||
let ext_var = var_store.fresh();
|
||||
|
@ -2464,7 +2465,8 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::Expr::Closure(_, loc_expr) => is_valid_interpolation(&loc_expr.value),
|
||||
ast::Expr::TupleAccess(sub_expr, _)
|
||||
| ast::Expr::ParensAround(sub_expr)
|
||||
| ast::Expr::RecordAccess(sub_expr, _) => is_valid_interpolation(sub_expr),
|
||||
| ast::Expr::RecordAccess(sub_expr, _)
|
||||
| ast::Expr::TaskAwaitBang(sub_expr) => is_valid_interpolation(sub_expr),
|
||||
ast::Expr::Apply(loc_expr, args, _called_via) => {
|
||||
is_valid_interpolation(&loc_expr.value)
|
||||
&& args
|
||||
|
|
|
@ -38,9 +38,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
| Num(..)
|
||||
| NonBase10Int { .. }
|
||||
| SingleQuote(_)
|
||||
| RecordAccess(_, _)
|
||||
| AccessorFunction(_)
|
||||
| TupleAccess(_, _)
|
||||
| Var { .. }
|
||||
| Underscore { .. }
|
||||
| MalformedIdent(_, _)
|
||||
|
@ -51,6 +49,10 @@ impl<'a> Formattable for Expr<'a> {
|
|||
| EmptyDefsFinal
|
||||
| Crash => false,
|
||||
|
||||
RecordAccess(inner, _) | TupleAccess(inner, _) | TaskAwaitBang(inner) => {
|
||||
inner.is_multiline()
|
||||
}
|
||||
|
||||
// These expressions always have newlines
|
||||
Defs(_, _) | When(_, _) => true,
|
||||
|
||||
|
@ -512,60 +514,18 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
}
|
||||
RecordAccess(expr, key) => {
|
||||
// Check for any `!` suffixes and format these at the end of expression
|
||||
let (expr_to_format, suffix_count) = if let Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} = expr
|
||||
{
|
||||
(
|
||||
Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed: 0,
|
||||
},
|
||||
suffixed,
|
||||
)
|
||||
} else {
|
||||
(**expr, &0u8)
|
||||
};
|
||||
|
||||
expr_to_format.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
buf.push('.');
|
||||
buf.push_str(key);
|
||||
|
||||
for _ in 0..*suffix_count {
|
||||
buf.push('!');
|
||||
}
|
||||
}
|
||||
TupleAccess(expr, key) => {
|
||||
// Check for any `!` suffixes and format these at the end of expression
|
||||
let (expr_to_format, suffix_count) = if let Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} = expr
|
||||
{
|
||||
(
|
||||
Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed: 0,
|
||||
},
|
||||
suffixed,
|
||||
)
|
||||
} else {
|
||||
(**expr, &0u8)
|
||||
};
|
||||
|
||||
expr_to_format.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
buf.push('.');
|
||||
buf.push_str(key);
|
||||
|
||||
for _ in 0..*suffix_count {
|
||||
buf.push('!');
|
||||
}
|
||||
}
|
||||
TaskAwaitBang(expr) => {
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
buf.push('!');
|
||||
}
|
||||
MalformedIdent(str, _) => {
|
||||
buf.indent(indent);
|
||||
|
|
|
@ -686,6 +686,7 @@ impl<'a> RemoveSpaces<'a> for Expr<'a> {
|
|||
Expr::RecordAccess(a, b) => Expr::RecordAccess(arena.alloc(a.remove_spaces(arena)), b),
|
||||
Expr::AccessorFunction(a) => Expr::AccessorFunction(a),
|
||||
Expr::TupleAccess(a, b) => Expr::TupleAccess(arena.alloc(a.remove_spaces(arena)), b),
|
||||
Expr::TaskAwaitBang(a) => Expr::TaskAwaitBang(arena.alloc(a.remove_spaces(arena))),
|
||||
Expr::List(a) => Expr::List(a.remove_spaces(arena)),
|
||||
Expr::RecordUpdate { update, fields } => Expr::RecordUpdate {
|
||||
update: arena.alloc(update.remove_spaces(arena)),
|
||||
|
|
|
@ -252,7 +252,7 @@ pub enum Expr<'a> {
|
|||
is_negative: bool,
|
||||
},
|
||||
|
||||
// String Literals
|
||||
/// String Literals
|
||||
Str(StrLiteral<'a>), // string without escapes in it
|
||||
/// eg 'b'
|
||||
SingleQuote(&'a str),
|
||||
|
@ -266,6 +266,9 @@ pub enum Expr<'a> {
|
|||
/// Look up exactly one field on a tuple, e.g. `(x, y).1`.
|
||||
TupleAccess(&'a Expr<'a>, &'a str),
|
||||
|
||||
/// Task await bang - i.e. the ! in `File.readUtf8! path`
|
||||
TaskAwaitBang(&'a Expr<'a>),
|
||||
|
||||
// Collection Literals
|
||||
List(Collection<'a, &'a Loc<Expr<'a>>>),
|
||||
|
||||
|
@ -1873,7 +1876,8 @@ impl<'a> Malformed for Expr<'a> {
|
|||
Str(inner) => inner.is_malformed(),
|
||||
|
||||
RecordAccess(inner, _) |
|
||||
TupleAccess(inner, _) => inner.is_malformed(),
|
||||
TupleAccess(inner, _) |
|
||||
TaskAwaitBang(inner) => inner.is_malformed(),
|
||||
|
||||
List(items) => items.is_malformed(),
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::blankspace::{
|
|||
space0_after_e, space0_around_e_no_after_indent_check, space0_around_ee, space0_before_e,
|
||||
space0_before_optional_after, space0_e, spaces, spaces_around, spaces_before,
|
||||
};
|
||||
use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident};
|
||||
use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident, Suffix};
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
self, backtrackable, byte, byte_indent, increment_min_indent, line_min_indent, optional,
|
||||
|
@ -135,7 +135,7 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>
|
|||
specialize_err(EExpr::InParens, loc_expr_in_parens_help()),
|
||||
record_field_access_chain()
|
||||
)),
|
||||
move |arena: &'a Bump, value: Loc<(Loc<Expr<'a>>, Vec<'a, Accessor<'a>>)>| {
|
||||
move |arena: &'a Bump, value: Loc<(Loc<Expr<'a>>, Vec<'a, Suffix<'a>>)>| {
|
||||
let Loc {
|
||||
mut region,
|
||||
value: (loc_expr, field_accesses),
|
||||
|
@ -156,16 +156,23 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>
|
|||
)
|
||||
}
|
||||
|
||||
fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EExpr<'a>> {
|
||||
zero_or_more!(skip_first!(
|
||||
byte(b'.', EExpr::Access),
|
||||
specialize_err(
|
||||
|_, pos| EExpr::Access(pos),
|
||||
one_of!(
|
||||
map!(lowercase_ident(), Accessor::RecordField),
|
||||
map!(integer_ident(), Accessor::TupleIndex),
|
||||
fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Suffix<'a>>, EExpr<'a>> {
|
||||
zero_or_more!(one_of!(
|
||||
skip_first!(
|
||||
byte(b'.', EExpr::Access),
|
||||
specialize_err(
|
||||
|_, pos| EExpr::Access(pos),
|
||||
one_of!(
|
||||
map!(lowercase_ident(), |x| Suffix::Accessor(
|
||||
Accessor::RecordField(x)
|
||||
)),
|
||||
map!(integer_ident(), |x| Suffix::Accessor(Accessor::TupleIndex(
|
||||
x
|
||||
))),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
map!(byte(b'!', EExpr::Access), |_| Suffix::TaskAwaitBang),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -188,10 +195,7 @@ fn loc_term_or_underscore_or_conditional<'a>(
|
|||
loc!(underscore_expression()),
|
||||
loc!(record_literal_help()),
|
||||
loc!(specialize_err(EExpr::List, list_literal_help())),
|
||||
loc!(map_with_arena!(
|
||||
assign_or_destructure_identifier(),
|
||||
ident_to_expr
|
||||
)),
|
||||
ident_seq(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -211,10 +215,7 @@ fn loc_term_or_underscore<'a>(
|
|||
loc!(underscore_expression()),
|
||||
loc!(record_literal_help()),
|
||||
loc!(specialize_err(EExpr::List, list_literal_help())),
|
||||
loc!(map_with_arena!(
|
||||
assign_or_destructure_identifier(),
|
||||
ident_to_expr
|
||||
)),
|
||||
ident_seq(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -229,13 +230,36 @@ fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EEx
|
|||
loc!(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc!(record_literal_help()),
|
||||
loc!(specialize_err(EExpr::List, list_literal_help())),
|
||||
loc!(map_with_arena!(
|
||||
assign_or_destructure_identifier(),
|
||||
ident_to_expr
|
||||
)),
|
||||
ident_seq(),
|
||||
)
|
||||
}
|
||||
|
||||
fn ident_seq<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
(|arena: &'a Bump, state: State<'a>, min_indent: u32| parse_ident_seq(arena, state, min_indent))
|
||||
.trace("ident_seq")
|
||||
}
|
||||
|
||||
fn parse_ident_seq<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
min_indent: u32,
|
||||
) -> ParseResult<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
let (p, loc_ident, state) =
|
||||
loc!(assign_or_destructure_identifier()).parse(arena, state, min_indent)?;
|
||||
let expr = ident_to_expr(arena, loc_ident.value);
|
||||
let (_p, suffixes, state) = record_field_access_chain()
|
||||
.trace("record_field_access_chain")
|
||||
.parse(arena, state, min_indent)
|
||||
.map_err(|(_p, e)| (MadeProgress, e))?;
|
||||
let expr = apply_expr_access_chain(arena, expr, suffixes);
|
||||
Ok((MadeProgress, Loc::at(loc_ident.region, expr), state))
|
||||
}
|
||||
// loc!(map_with_arena!(
|
||||
// assign_or_destructure_identifier(),
|
||||
// ident_to_expr
|
||||
// ))
|
||||
// }
|
||||
|
||||
fn underscore_expression<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let start = state.pos();
|
||||
|
@ -2249,6 +2273,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::UnappliedRecordBuilder { .. }
|
||||
| Expr::RecordUpdate { .. }
|
||||
| Expr::UnaryOp(_, _)
|
||||
| Expr::TaskAwaitBang(..)
|
||||
| Expr::Crash => return Err(()),
|
||||
|
||||
Expr::Str(string) => Pattern::StrLiteral(string),
|
||||
|
@ -3174,13 +3199,18 @@ fn record_builder_help<'a>(
|
|||
fn apply_expr_access_chain<'a>(
|
||||
arena: &'a Bump,
|
||||
value: Expr<'a>,
|
||||
accessors: Vec<'a, Accessor<'a>>,
|
||||
accessors: Vec<'a, Suffix<'a>>,
|
||||
) -> Expr<'a> {
|
||||
accessors
|
||||
.into_iter()
|
||||
.fold(value, |value, accessor| match accessor {
|
||||
Accessor::RecordField(field) => Expr::RecordAccess(arena.alloc(value), field),
|
||||
Accessor::TupleIndex(field) => Expr::TupleAccess(arena.alloc(value), field),
|
||||
Suffix::Accessor(Accessor::RecordField(field)) => {
|
||||
Expr::RecordAccess(arena.alloc(value), field)
|
||||
}
|
||||
Suffix::Accessor(Accessor::TupleIndex(field)) => {
|
||||
Expr::TupleAccess(arena.alloc(value), field)
|
||||
}
|
||||
Suffix::TaskAwaitBang => Expr::TaskAwaitBang(arena.alloc(value)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -388,6 +388,12 @@ impl<'a> Accessor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Suffix<'a> {
|
||||
Accessor(Accessor<'a>),
|
||||
TaskAwaitBang,
|
||||
}
|
||||
|
||||
/// a `.foo` or `.1` accessor function
|
||||
fn chomp_accessor(buffer: &[u8], pos: Position) -> Result<Accessor, BadIdent> {
|
||||
// assumes the leading `.` has been chomped already
|
||||
|
@ -529,16 +535,16 @@ fn chomp_identifier_chain<'a>(
|
|||
chomped += width as usize;
|
||||
|
||||
// Parse any `!` suffixes
|
||||
let mut suffixed = 0;
|
||||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if ch == '!' {
|
||||
suffixed += 1;
|
||||
chomped += width;
|
||||
} else {
|
||||
// we're done
|
||||
break;
|
||||
}
|
||||
}
|
||||
let suffixed = 0;
|
||||
// while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
// if ch == '!' {
|
||||
// suffixed += 1;
|
||||
// chomped += width;
|
||||
// } else {
|
||||
// // we're done
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
let ident = Ident::Access {
|
||||
module_name,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue