mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
Merge remote-tracking branch 'origin/main' into https-packages
This commit is contained in:
commit
bef59299a2
@ -535,8 +535,8 @@ pub enum TypeAnnotation<'a> {
|
||||
|
||||
Tuple {
|
||||
fields: Collection<'a, Loc<TypeAnnotation<'a>>>,
|
||||
/// The row type variable in an open record, e.g. the `r` in `{ name: Str }r`.
|
||||
/// This is None if it's a closed record annotation like `{ name: Str }`.
|
||||
/// The row type variable in an open tuple, e.g. the `r` in `( Str, Str )r`.
|
||||
/// This is None if it's a closed tuple annotation like `( Str, Str )`.
|
||||
ext: Option<&'a Loc<TypeAnnotation<'a>>>,
|
||||
},
|
||||
|
||||
|
@ -6,7 +6,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,
|
||||
};
|
||||
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
||||
use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident};
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
self, backtrackable, increment_min_indent, line_min_indent, optional, reset_min_indent,
|
||||
@ -124,13 +124,9 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>
|
||||
map_with_arena!(
|
||||
loc!(and!(
|
||||
specialize(EExpr::InParens, loc_expr_in_parens_help()),
|
||||
one_of![record_field_access_chain(), |a, s, _m| Ok((
|
||||
NoProgress,
|
||||
Vec::new_in(a),
|
||||
s
|
||||
))]
|
||||
record_field_access_chain()
|
||||
)),
|
||||
move |arena: &'a Bump, value: Loc<(Loc<Expr<'a>>, Vec<'a, &'a str>)>| {
|
||||
move |arena: &'a Bump, value: Loc<(Loc<Expr<'a>>, Vec<'a, Accessor<'a>>)>| {
|
||||
let Loc {
|
||||
mut region,
|
||||
value: (loc_expr, field_accesses),
|
||||
@ -143,12 +139,7 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>
|
||||
if field_accesses.is_empty() {
|
||||
region = loc_expr.region;
|
||||
} else {
|
||||
for field in field_accesses {
|
||||
// Wrap the previous answer in the new one, so we end up
|
||||
// with a nested Expr. That way, `foo.bar.baz` gets represented
|
||||
// in the AST as if it had been written (foo.bar).baz all along.
|
||||
value = Expr::RecordAccess(arena.alloc(value), field);
|
||||
}
|
||||
value = apply_expr_access_chain(arena, value, field_accesses);
|
||||
}
|
||||
|
||||
Loc::at(region, value)
|
||||
@ -156,39 +147,17 @@ 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, &'a str>, EExpr<'a>> {
|
||||
|arena, state: State<'a>, min_indent| match record_field_access().parse(
|
||||
arena,
|
||||
state.clone(),
|
||||
min_indent,
|
||||
) {
|
||||
Ok((_, initial, state)) => {
|
||||
let mut accesses = Vec::with_capacity_in(1, arena);
|
||||
|
||||
accesses.push(initial);
|
||||
|
||||
let mut loop_state = state;
|
||||
loop {
|
||||
match record_field_access().parse(arena, loop_state.clone(), min_indent) {
|
||||
Ok((_, next, state)) => {
|
||||
accesses.push(next);
|
||||
loop_state = state;
|
||||
}
|
||||
Err((MadeProgress, fail)) => return Err((MadeProgress, fail)),
|
||||
Err((NoProgress, _)) => return Ok((MadeProgress, accesses, loop_state)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
|
||||
Err((NoProgress, _)) => Err((NoProgress, EExpr::Access(state.pos()))),
|
||||
}
|
||||
}
|
||||
|
||||
fn record_field_access<'a>() -> impl Parser<'a, &'a str, EExpr<'a>> {
|
||||
skip_first!(
|
||||
fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EExpr<'a>> {
|
||||
zero_or_more!(skip_first!(
|
||||
word1(b'.', EExpr::Access),
|
||||
specialize(|_, pos| EExpr::Access(pos), lowercase_ident())
|
||||
)
|
||||
specialize(
|
||||
|_, pos| EExpr::Access(pos),
|
||||
one_of!(
|
||||
map!(lowercase_ident(), Accessor::RecordField),
|
||||
map!(integer_ident(), Accessor::TupleIndex),
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
/// In some contexts we want to parse the `_` as an expression, so it can then be turned into a
|
||||
@ -2621,13 +2590,13 @@ fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
and!(
|
||||
loc!(specialize(EExpr::Record, record_help())),
|
||||
// there can be field access, e.g. `{ x : 4 }.x`
|
||||
optional(record_field_access_chain())
|
||||
record_field_access_chain()
|
||||
),
|
||||
move |arena, state, _, (loc_record, accesses)| {
|
||||
move |arena, state, _, (loc_record, accessors)| {
|
||||
let (opt_update, loc_assigned_fields_with_comments) = loc_record.value;
|
||||
|
||||
// This is a record literal, not a destructure.
|
||||
let mut value = match opt_update {
|
||||
let value = match opt_update {
|
||||
Some(update) => Expr::RecordUpdate {
|
||||
update: &*arena.alloc(update),
|
||||
fields: Collection::with_items_and_comments(
|
||||
@ -2643,20 +2612,26 @@ fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
)),
|
||||
};
|
||||
|
||||
if let Some(fields) = accesses {
|
||||
for field in fields {
|
||||
// Wrap the previous answer in the new one, so we end up
|
||||
// with a nested Expr. That way, `foo.bar.baz` gets represented
|
||||
// in the AST as if it had been written (foo.bar).baz all along.
|
||||
value = Expr::RecordAccess(arena.alloc(value), field);
|
||||
}
|
||||
}
|
||||
let value = apply_expr_access_chain(arena, value, accessors);
|
||||
|
||||
Ok((MadeProgress, value, state))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn apply_expr_access_chain<'a>(
|
||||
arena: &'a Bump,
|
||||
value: Expr<'a>,
|
||||
accessors: Vec<'a, Accessor<'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),
|
||||
})
|
||||
}
|
||||
|
||||
fn string_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> {
|
||||
map!(crate::string_literal::parse(), Expr::Str)
|
||||
}
|
||||
|
@ -100,6 +100,17 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a tuple accessor, e.g. "1" in `.1`
|
||||
pub fn integer_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
move |_, state: State<'a>, _min_indent: u32| match chomp_integer_part(state.bytes()) {
|
||||
Err(progress) => Err((progress, ())),
|
||||
Ok(ident) => {
|
||||
let width = ident.len();
|
||||
Ok((MadeProgress, ident, state.advance(width)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag_name<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
uppercase_ident().parse(arena, state, min_indent)
|
||||
|
@ -1791,7 +1791,7 @@ macro_rules! one_or_more {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
match $parser.parse(arena, state, min_indent) {
|
||||
match $parser.parse(arena, state.clone(), min_indent) {
|
||||
Ok((_, first_output, next_state)) => {
|
||||
let mut state = next_state;
|
||||
let mut buf = Vec::with_capacity_in(1, arena);
|
||||
@ -1809,14 +1809,12 @@ macro_rules! one_or_more {
|
||||
return Ok((MadeProgress, buf, old_state));
|
||||
}
|
||||
Err((MadeProgress, fail)) => {
|
||||
return Err((MadeProgress, fail, old_state));
|
||||
return Err((MadeProgress, fail));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err((progress, _, new_state)) => {
|
||||
Err((progress, $to_error(new_state.pos), new_state))
|
||||
}
|
||||
Err((progress, _)) => Err((progress, $to_error(state.pos()))),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1 @@
|
||||
({ a: 0 }, { b: 1 }).0.a
|
@ -0,0 +1,32 @@
|
||||
RecordAccess(
|
||||
TupleAccess(
|
||||
Tuple(
|
||||
[
|
||||
@1-7 Record(
|
||||
[
|
||||
@2-6 RequiredValue(
|
||||
@2-3 "a",
|
||||
[],
|
||||
@5-6 Num(
|
||||
"0",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@9-15 Record(
|
||||
[
|
||||
@10-14 RequiredValue(
|
||||
@10-11 "b",
|
||||
[],
|
||||
@13-14 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
"0",
|
||||
),
|
||||
"a",
|
||||
)
|
@ -0,0 +1 @@
|
||||
({a: 0}, {b: 1}).0.a
|
@ -0,0 +1,24 @@
|
||||
TupleAccess(
|
||||
RecordAccess(
|
||||
Record(
|
||||
[
|
||||
@2-11 RequiredValue(
|
||||
@2-3 "a",
|
||||
[],
|
||||
@5-11 Tuple(
|
||||
[
|
||||
@6-7 Num(
|
||||
"1",
|
||||
),
|
||||
@9-10 Num(
|
||||
"2",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
"a",
|
||||
),
|
||||
"0",
|
||||
)
|
@ -0,0 +1 @@
|
||||
{ a: (1, 2) }.a.0
|
@ -188,6 +188,8 @@ mod test_parse {
|
||||
pass/lowest_float.expr,
|
||||
pass/lowest_int.expr,
|
||||
pass/tuple_type.expr,
|
||||
pass/tuple_access_after_record.expr,
|
||||
pass/record_access_after_tuple.expr,
|
||||
pass/tuple_type_ext.expr,
|
||||
pass/malformed_ident_due_to_underscore.expr,
|
||||
pass/malformed_pattern_field_access.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
|
@ -183,7 +183,7 @@ impl<'a> Renderer<'a> {
|
||||
let line_col_region = self.to_line_col_region(expect_region, dbg_expr_region);
|
||||
write!(
|
||||
writer,
|
||||
"[{} {}:{}] = ",
|
||||
"\u{001b}[36m[{} {}:{}] \u{001b}[0m",
|
||||
self.filename.display(),
|
||||
line_col_region.start.line,
|
||||
line_col_region.start.column
|
||||
@ -197,7 +197,7 @@ impl<'a> Renderer<'a> {
|
||||
expr.format(&mut buf, 0);
|
||||
}
|
||||
|
||||
write!(writer, "{}", buf.as_str())
|
||||
writeln!(writer, "{}", buf.as_str())
|
||||
}
|
||||
|
||||
pub fn render_panic<W>(
|
||||
|
Loading…
Reference in New Issue
Block a user