Merge branch 'main' into format-invisible-chars

This commit is contained in:
Joshua Warner 2024-08-17 10:22:40 -07:00 committed by GitHub
commit 6b6968632f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 384 additions and 178 deletions

View file

@ -432,6 +432,9 @@ pub enum Expr<'a> {
/// e.g. `.foo` or `.0`
AccessorFunction(Accessor<'a>),
/// Update the value of a field in a record, e.g. `&foo`
RecordUpdater(&'a str),
/// Look up exactly one field on a tuple, e.g. `(x, y).1`.
TupleAccess(&'a Expr<'a>, &'a str),
@ -636,6 +639,7 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
Expr::SingleQuote(_) => false,
Expr::RecordAccess(a, _) => is_expr_suffixed(a),
Expr::AccessorFunction(_) => false,
Expr::RecordUpdater(_) => false,
Expr::TupleAccess(a, _) => is_expr_suffixed(a),
Expr::List(items) => items.iter().any(|x| is_expr_suffixed(&x.value)),
Expr::RecordUpdate { update, fields } => {
@ -1024,6 +1028,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
| Str(_)
| SingleQuote(_)
| AccessorFunction(_)
| RecordUpdater(_)
| Var { .. }
| Underscore(_)
| Crash
@ -2487,6 +2492,7 @@ impl<'a> Malformed for Expr<'a> {
Num(_) |
NonBase10Int { .. } |
AccessorFunction(_) |
RecordUpdater(_) |
Var { .. } |
Underscore(_) |
Tag(_) |

View file

@ -2181,6 +2181,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
| Expr::SingleFieldRecordBuilder(_)
| Expr::OptionalFieldInRecordBuilder(_, _)
| Expr::RecordUpdate { .. }
| Expr::RecordUpdater(_)
| Expr::UnaryOp(_, _)
| Expr::TrySuffix { .. }
| Expr::Crash
@ -3251,7 +3252,7 @@ pub fn join_alias_to_body<'a>(
/// 2. The beginning of a function call (e.g. `foo bar baz`)
/// 3. The beginning of a definition (e.g. `foo =`)
/// 4. The beginning of a type annotation (e.g. `foo :`)
/// 5. A reserved keyword (e.g. `if ` or `case `), meaning we should do something else.
/// 5. A reserved keyword (e.g. `if ` or `when `), meaning we should do something else.
fn assign_or_destructure_identifier<'a>() -> impl Parser<'a, Ident<'a>, EExpr<'a>> {
parse_ident
@ -3313,6 +3314,7 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
answer
}
Ident::AccessorFunction(string) => Expr::AccessorFunction(string),
Ident::RecordUpdaterFunction(string) => Expr::RecordUpdater(string),
Ident::Malformed(string, problem) => Expr::MalformedIdent(string, problem),
}
}

View file

@ -46,42 +46,12 @@ pub enum Ident<'a> {
},
/// `.foo { foo: 42 }` or `.1 (1, 2, 3)`
AccessorFunction(Accessor<'a>),
/// `&foo { foo: 42 } 3`
RecordUpdaterFunction(&'a str),
/// .Foo or foo. or something like foo.Bar
Malformed(&'a str, BadIdent),
}
impl<'a> Ident<'a> {
pub fn len(&self) -> usize {
use self::Ident::*;
match self {
Tag(string) | OpaqueRef(string) => string.len(),
Access {
module_name, parts, ..
} => {
let mut len = if module_name.is_empty() {
0
} else {
module_name.len() + 1
// +1 for the dot
};
for part in parts.iter() {
len += part.len() + 1 // +1 for the dot
}
len - 1
}
AccessorFunction(string) => string.len(),
Malformed(string, _) => string.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
/// This could be:
///
/// * A record field, e.g. "email" in `.email` or in `email:`
@ -272,6 +242,7 @@ pub enum BadIdent {
WeirdDotAccess(Position),
WeirdDotQualified(Position),
StrayDot(Position),
StrayAmpersand(Position),
BadOpaqueRef(Position),
QualifiedTupleAccessor(Position),
}
@ -416,6 +387,18 @@ fn chomp_accessor(buffer: &[u8], pos: Position) -> Result<Accessor, BadIdent> {
}
}
/// a `&foo` record updater function
fn chomp_record_updater(buffer: &[u8], pos: Position) -> Result<&str, BadIdent> {
// assumes the leading `&` has been chomped already
match chomp_lowercase_part(buffer) {
Ok(name) => Ok(name),
Err(_) => {
// we've already made progress with the initial `&`
Err(BadIdent::StrayAmpersand(pos.bump_column(1)))
}
}
}
/// a `@Token` opaque
fn chomp_opaque_ref(buffer: &[u8], pos: Position) -> Result<&str, BadIdent> {
// assumes the leading `@` has NOT been chomped already
@ -458,6 +441,14 @@ fn chomp_identifier_chain<'a>(
}
Err(fail) => return Err((1, fail)),
},
'&' => match chomp_record_updater(&buffer[1..], pos) {
Ok(updater) => {
let bytes_parsed = 1 + updater.len();
return Ok((bytes_parsed as u32, Ident::RecordUpdaterFunction(updater)));
}
// return 0 bytes consumed on failure to allow parsing &&
Err(fail) => return Err((0, fail)),
},
'@' => match chomp_opaque_ref(buffer, pos) {
Ok(tagname) => {
let bytes_parsed = tagname.len();

View file

@ -731,6 +731,7 @@ impl<'a> Normalize<'a> for Expr<'a> {
Expr::Str(a) => Expr::Str(a.normalize(arena)),
Expr::RecordAccess(a, b) => Expr::RecordAccess(arena.alloc(a.normalize(arena)), b),
Expr::AccessorFunction(a) => Expr::AccessorFunction(a),
Expr::RecordUpdater(a) => Expr::RecordUpdater(a),
Expr::TupleAccess(a, b) => Expr::TupleAccess(arena.alloc(a.normalize(arena)), b),
Expr::TrySuffix { expr: a, target } => Expr::TrySuffix {
expr: arena.alloc(a.normalize(arena)),
@ -850,6 +851,7 @@ fn remove_spaces_bad_ident(ident: BadIdent) -> BadIdent {
BadIdent::WeirdDotAccess(_) => BadIdent::WeirdDotAccess(Position::zero()),
BadIdent::WeirdDotQualified(_) => BadIdent::WeirdDotQualified(Position::zero()),
BadIdent::StrayDot(_) => BadIdent::StrayDot(Position::zero()),
BadIdent::StrayAmpersand(_) => BadIdent::StrayAmpersand(Position::zero()),
BadIdent::BadOpaqueRef(_) => BadIdent::BadOpaqueRef(Position::zero()),
BadIdent::QualifiedTupleAccessor(_) => BadIdent::QualifiedTupleAccessor(Position::zero()),
}
@ -1237,6 +1239,7 @@ impl<'a> Normalize<'a> for EPattern<'a> {
EPattern::IndentEnd(_) => EPattern::IndentEnd(Position::zero()),
EPattern::AsIndentStart(_) => EPattern::AsIndentStart(Position::zero()),
EPattern::AccessorFunction(_) => EPattern::AccessorFunction(Position::zero()),
EPattern::RecordUpdaterFunction(_) => EPattern::RecordUpdaterFunction(Position::zero()),
}
}
}

View file

@ -605,6 +605,7 @@ pub enum EPattern<'a> {
AsIndentStart(Position),
AccessorFunction(Position),
RecordUpdaterFunction(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]

View file

@ -436,6 +436,10 @@ fn loc_ident_pattern_help<'a>(
MadeProgress,
EPattern::AccessorFunction(loc_ident.region.start()),
)),
Ident::RecordUpdaterFunction(_string) => Err((
MadeProgress,
EPattern::RecordUpdaterFunction(loc_ident.region.start()),
)),
Ident::Malformed(malformed, problem) => {
debug_assert!(!malformed.is_empty());