Fix parsing of tuple accessors after an identifier - e.g. myIdent.2

This commit is contained in:
Joshua Warner 2023-01-30 20:21:50 -08:00
parent 53b1525139
commit 31a4eb2bfd
No known key found for this signature in database
GPG key ID: 89AD497003F93FDD
8 changed files with 150 additions and 59 deletions

View file

@ -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),
}