move suffixed parsing into chomp_identifier_chain

This commit is contained in:
Luke Boswell 2024-03-22 19:19:59 +11:00
parent d988eadbb1
commit 370ac1e6b8
No known key found for this signature in database
GPG key ID: F6DB3C9DB47377B0
4 changed files with 43 additions and 17 deletions

View file

@ -1829,18 +1829,6 @@ fn parse_expr_end<'a>(
} }
} }
} }
.map(|(progress, expr, state)| {
// If the next thing after the expression is a `!`, then it's Suffixed
if state.bytes().starts_with(b"!") {
(
progress,
Expr::Suffixed(arena.alloc(expr)),
state.advance(1),
)
} else {
(progress, expr, state)
}
})
} }
pub fn loc_expr<'a>(accept_multi_backpassing: bool) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> { pub fn loc_expr<'a>(accept_multi_backpassing: bool) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
@ -2510,12 +2498,19 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
match src { match src {
Ident::Tag(string) => Expr::Tag(string), Ident::Tag(string) => Expr::Tag(string),
Ident::OpaqueRef(string) => Expr::OpaqueRef(string), Ident::OpaqueRef(string) => Expr::OpaqueRef(string),
Ident::Access { module_name, parts } => { Ident::Access {
module_name,
parts,
suffixed,
} => {
let mut iter = parts.iter(); let mut iter = parts.iter();
// The first value in the iterator is the variable name, // The first value in the iterator is the variable name,
// e.g. `foo` in `foo.bar.baz` // e.g. `foo` in `foo.bar.baz`
let mut answer = match iter.next() { let mut answer = match iter.next() {
Some(Accessor::RecordField(ident)) if suffixed => {
Expr::Suffixed(arena.alloc(Expr::Var { module_name, ident }))
}
Some(Accessor::RecordField(ident)) => Expr::Var { module_name, ident }, Some(Accessor::RecordField(ident)) => Expr::Var { module_name, ident },
Some(Accessor::TupleIndex(_)) => { Some(Accessor::TupleIndex(_)) => {
// TODO: make this state impossible to represent in Ident::Access, // TODO: make this state impossible to represent in Ident::Access,

View file

@ -42,6 +42,7 @@ pub enum Ident<'a> {
Access { Access {
module_name: &'a str, module_name: &'a str,
parts: &'a [Accessor<'a>], parts: &'a [Accessor<'a>],
suffixed: bool,
}, },
/// `.foo { foo: 42 }` or `.1 (1, 2, 3)` /// `.foo { foo: 42 }` or `.1 (1, 2, 3)`
AccessorFunction(Accessor<'a>), AccessorFunction(Accessor<'a>),
@ -55,7 +56,9 @@ impl<'a> Ident<'a> {
match self { match self {
Tag(string) | OpaqueRef(string) => string.len(), Tag(string) | OpaqueRef(string) => string.len(),
Access { module_name, parts } => { Access {
module_name, parts, ..
} => {
let mut len = if module_name.is_empty() { let mut len = if module_name.is_empty() {
0 0
} else { } else {
@ -190,7 +193,10 @@ pub fn parse_ident<'a>(
match chomp_identifier_chain(arena, state.bytes(), state.pos()) { match chomp_identifier_chain(arena, state.bytes(), state.pos()) {
Ok((width, ident)) => { Ok((width, ident)) => {
let state = advance_state!(state, width as usize)?; let state = advance_state!(state, width as usize)?;
if let Ident::Access { module_name, parts } = ident { if let Ident::Access {
module_name, parts, ..
} = ident
{
if module_name.is_empty() { if module_name.is_empty() {
if let Some(first) = parts.first() { if let Some(first) = parts.first() {
for keyword in crate::keyword::KEYWORDS.iter() { for keyword in crate::keyword::KEYWORDS.iter() {
@ -202,6 +208,21 @@ pub fn parse_ident<'a>(
} }
} }
// Parse a suffixed `!` expression
if state.bytes().starts_with(b"!") {
if let Ident::Access {
module_name, parts, ..
} = ident
{
let new_ident = Ident::Access {
module_name,
parts,
suffixed: true,
};
return Ok((MadeProgress, new_ident, state.advance(1)));
}
}
Ok((MadeProgress, ident, state)) Ok((MadeProgress, ident, state))
} }
Err((0, _)) => Err((NoProgress, EExpr::Start(state.pos()))), Err((0, _)) => Err((NoProgress, EExpr::Start(state.pos()))),
@ -513,6 +534,7 @@ fn chomp_identifier_chain<'a>(
let ident = Ident::Access { let ident = Ident::Access {
module_name, module_name,
parts: parts.into_bump_slice(), parts: parts.into_bump_slice(),
suffixed: false,
}; };
Ok((chomped as u32, ident)) Ok((chomped as u32, ident))
@ -548,6 +570,7 @@ fn chomp_identifier_chain<'a>(
let ident = Ident::Access { let ident = Ident::Access {
module_name: "", module_name: "",
parts: arena.alloc([Accessor::RecordField(value)]), parts: arena.alloc([Accessor::RecordField(value)]),
suffixed: false,
}; };
Ok((chomped as u32, ident)) Ok((chomped as u32, ident))
} }

View file

@ -381,7 +381,9 @@ fn loc_ident_pattern_help<'a>(
Ok((MadeProgress, loc_pat, state)) Ok((MadeProgress, loc_pat, state))
} }
} }
Ident::Access { module_name, parts } => { Ident::Access {
module_name, parts, ..
} => {
// Plain identifiers (e.g. `foo`) are allowed in patterns, but // Plain identifiers (e.g. `foo`) are allowed in patterns, but
// more complex ones (e.g. `Foo.bar` or `foo.bar.baz`) are not. // more complex ones (e.g. `Foo.bar` or `foo.bar.baz`) are not.

View file

@ -999,7 +999,13 @@ fn markdown_to_html(
arena.reset(); arena.reset();
match parse_ident(&arena, state, 0) { match parse_ident(&arena, state, 0) {
Ok((_, Ident::Access { module_name, parts }, _)) => { Ok((
_,
Ident::Access {
module_name, parts, ..
},
_,
)) => {
let mut iter = parts.iter(); let mut iter = parts.iter();
match iter.next() { match iter.next() {