mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Parse opaque references
This commit is contained in:
parent
a38f1d1e8d
commit
6104a27b45
22 changed files with 206 additions and 25 deletions
|
@ -38,6 +38,8 @@ pub enum Ident<'a> {
|
|||
GlobalTag(&'a str),
|
||||
/// @Foo or @Bar
|
||||
PrivateTag(&'a str),
|
||||
/// $Foo or $Bar
|
||||
OpaqueRef(&'a str),
|
||||
/// foo or foo.bar or Foo.Bar.baz.qux
|
||||
Access {
|
||||
module_name: &'a str,
|
||||
|
@ -54,7 +56,7 @@ impl<'a> Ident<'a> {
|
|||
use self::Ident::*;
|
||||
|
||||
match self {
|
||||
GlobalTag(string) | PrivateTag(string) => string.len(),
|
||||
GlobalTag(string) | PrivateTag(string) | OpaqueRef(string) => string.len(),
|
||||
Access { module_name, parts } => {
|
||||
let mut len = if module_name.is_empty() {
|
||||
0
|
||||
|
@ -100,7 +102,11 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
|||
pub fn tag_name<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
move |arena, state: State<'a>| {
|
||||
if state.bytes().starts_with(b"@") {
|
||||
match chomp_private_tag(state.bytes(), state.pos()) {
|
||||
match chomp_private_tag_or_opaque(
|
||||
/* private tag */ true,
|
||||
state.bytes(),
|
||||
state.pos(),
|
||||
) {
|
||||
Err(BadIdent::Start(_)) => Err((NoProgress, (), state)),
|
||||
Err(_) => Err((MadeProgress, (), state)),
|
||||
Ok(ident) => {
|
||||
|
@ -236,6 +242,7 @@ pub enum BadIdent {
|
|||
WeirdDotQualified(Position),
|
||||
StrayDot(Position),
|
||||
BadPrivateTag(Position),
|
||||
BadOpaqueRef(Position),
|
||||
}
|
||||
|
||||
fn chomp_lowercase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
|
@ -304,23 +311,33 @@ fn chomp_accessor(buffer: &[u8], pos: Position) -> Result<&str, BadIdent> {
|
|||
}
|
||||
|
||||
/// a `@Token` private tag
|
||||
fn chomp_private_tag(buffer: &[u8], pos: Position) -> Result<&str, BadIdent> {
|
||||
fn chomp_private_tag_or_opaque(
|
||||
private_tag: bool, // If false, opaque
|
||||
buffer: &[u8],
|
||||
pos: Position,
|
||||
) -> Result<&str, BadIdent> {
|
||||
// assumes the leading `@` has NOT been chomped already
|
||||
debug_assert_eq!(buffer.get(0), Some(&b'@'));
|
||||
debug_assert_eq!(buffer.get(0), Some(if private_tag { &b'@' } else { &b'$' }));
|
||||
use encode_unicode::CharExt;
|
||||
|
||||
let bad_ident = if private_tag {
|
||||
BadIdent::BadPrivateTag
|
||||
} else {
|
||||
BadIdent::BadOpaqueRef
|
||||
};
|
||||
|
||||
match chomp_uppercase_part(&buffer[1..]) {
|
||||
Ok(name) => {
|
||||
let width = 1 + name.len();
|
||||
|
||||
if let Ok(('.', _)) = char::from_utf8_slice_start(&buffer[width..]) {
|
||||
Err(BadIdent::BadPrivateTag(pos.bump_column(width as u32)))
|
||||
Err(bad_ident(pos.bump_column(width as u32)))
|
||||
} else {
|
||||
let value = unsafe { std::str::from_utf8_unchecked(&buffer[..width]) };
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
Err(_) => Err(BadIdent::BadPrivateTag(pos.bump_column(1))),
|
||||
Err(_) => Err(bad_ident(pos.bump_column(1))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,11 +361,17 @@ fn chomp_identifier_chain<'a>(
|
|||
}
|
||||
Err(fail) => return Err((1, fail)),
|
||||
},
|
||||
'@' => match chomp_private_tag(buffer, pos) {
|
||||
c @ ('@' | '$') => match chomp_private_tag_or_opaque(c == '@', buffer, pos) {
|
||||
Ok(tagname) => {
|
||||
let bytes_parsed = tagname.len();
|
||||
|
||||
return Ok((bytes_parsed as u32, Ident::PrivateTag(tagname)));
|
||||
let ident = if c == '@' {
|
||||
Ident::PrivateTag
|
||||
} else {
|
||||
Ident::OpaqueRef
|
||||
};
|
||||
|
||||
return Ok((bytes_parsed as u32, ident(tagname)));
|
||||
}
|
||||
Err(fail) => return Err((1, fail)),
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue