mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Fix parsing of tuple accessors after an identifier - e.g. myIdent.2
This commit is contained in:
parent
53b1525139
commit
31a4eb2bfd
8 changed files with 150 additions and 59 deletions
|
@ -41,7 +41,7 @@ pub enum Ident<'a> {
|
|||
/// foo or foo.bar or Foo.Bar.baz.qux
|
||||
Access {
|
||||
module_name: &'a str,
|
||||
parts: &'a [&'a str],
|
||||
parts: &'a [Accessor<'a>],
|
||||
},
|
||||
/// .foo { foo: 42 }
|
||||
RecordAccessorFunction(&'a str),
|
||||
|
@ -197,7 +197,7 @@ pub fn parse_ident<'a>(
|
|||
if module_name.is_empty() {
|
||||
if let Some(first) = parts.first() {
|
||||
for keyword in crate::keyword::KEYWORDS.iter() {
|
||||
if first == keyword {
|
||||
if first == &Accessor::RecordField(keyword) {
|
||||
return Err((NoProgress, EExpr::Start(initial.pos())));
|
||||
}
|
||||
}
|
||||
|
@ -339,11 +339,32 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Accessor<'a> {
|
||||
RecordField(&'a str),
|
||||
TupleIndex(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> Accessor<'a> {
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Accessor::RecordField(name) => name.len(),
|
||||
Accessor::TupleIndex(name) => name.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() > 0
|
||||
}
|
||||
|
||||
pub fn as_inner(&self) -> &'a str {
|
||||
match self {
|
||||
Accessor::RecordField(name) => name,
|
||||
Accessor::TupleIndex(name) => name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// a `.foo` or `.1` accessor function
|
||||
fn chomp_accessor(buffer: &[u8], pos: Position) -> Result<Accessor, BadIdent> {
|
||||
// assumes the leading `.` has been chomped already
|
||||
|
@ -474,7 +495,7 @@ fn chomp_identifier_chain<'a>(
|
|||
|
||||
if !first_is_uppercase {
|
||||
let first_part = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
||||
parts.push(first_part);
|
||||
parts.push(Accessor::RecordField(first_part));
|
||||
}
|
||||
|
||||
match chomp_access_chain(&buffer[chomped..], &mut parts) {
|
||||
|
@ -518,7 +539,7 @@ fn chomp_identifier_chain<'a>(
|
|||
let value = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
||||
let ident = Ident::Access {
|
||||
module_name: "",
|
||||
parts: arena.alloc([value]),
|
||||
parts: arena.alloc([Accessor::RecordField(value)]),
|
||||
};
|
||||
Ok((chomped as u32, ident))
|
||||
}
|
||||
|
@ -591,7 +612,7 @@ fn chomp_concrete_type(buffer: &[u8]) -> Result<(&str, &str, usize), Progress> {
|
|||
}
|
||||
}
|
||||
|
||||
fn chomp_access_chain<'a>(buffer: &'a [u8], parts: &mut Vec<'a, &'a str>) -> Result<u32, u32> {
|
||||
fn chomp_access_chain<'a>(buffer: &'a [u8], parts: &mut Vec<'a, Accessor<'a>>) -> Result<u32, u32> {
|
||||
let mut chomped = 0;
|
||||
|
||||
while let Some(b'.') = buffer.get(chomped) {
|
||||
|
@ -603,11 +624,23 @@ fn chomp_access_chain<'a>(buffer: &'a [u8], parts: &mut Vec<'a, &'a str>) -> Res
|
|||
&buffer[chomped + 1..chomped + 1 + name.len()],
|
||||
)
|
||||
};
|
||||
parts.push(value);
|
||||
parts.push(Accessor::RecordField(value));
|
||||
|
||||
chomped += name.len() + 1;
|
||||
}
|
||||
Err(_) => return Err(chomped as u32 + 1),
|
||||
Err(_) => match chomp_integer_part(slice) {
|
||||
Ok(name) => {
|
||||
let value = unsafe {
|
||||
std::str::from_utf8_unchecked(
|
||||
&buffer[chomped + 1..chomped + 1 + name.len()],
|
||||
)
|
||||
};
|
||||
parts.push(Accessor::TupleIndex(value));
|
||||
|
||||
chomped += name.len() + 1;
|
||||
}
|
||||
Err(_) => return Err(chomped as u32 + 1),
|
||||
},
|
||||
},
|
||||
None => return Err(chomped as u32 + 1),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue