This commit is contained in:
Folkert 2021-03-10 00:26:54 +01:00
parent 91271d0308
commit 4b8f5fb477

View file

@ -2,13 +2,10 @@ use crate::ast::{CommentOrNewline, Spaceable, StrLiteral, TypeAnnotation};
use crate::blankspace::space0; use crate::blankspace::space0;
use crate::ident::lowercase_ident; use crate::ident::lowercase_ident;
use crate::parser::{ use crate::parser::{
ascii_char, optional, peek_utf8_char, specialize, unexpected_eof, Either, ParseResult, Parser, ascii_char, optional, specialize, Either, Parser, Progress, Progress::*, State, SyntaxError,
Progress, Progress::*, State, SyntaxError,
}; };
use crate::string_literal; use crate::string_literal;
use bumpalo::collections::String;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump;
use inlinable_string::InlinableString; use inlinable_string::InlinableString;
use roc_region::all::Loc; use roc_region::all::Loc;
@ -274,24 +271,22 @@ pub fn package_entry<'a>() -> impl Parser<'a, PackageEntry<'a>, SyntaxError<'a>>
} }
pub fn package_or_path<'a>() -> impl Parser<'a, PackageOrPath<'a>, SyntaxError<'a>> { pub fn package_or_path<'a>() -> impl Parser<'a, PackageOrPath<'a>, SyntaxError<'a>> {
one_of![
map!( map!(
either!(
specialize( specialize(
|e, r, c| SyntaxError::Expr(crate::parser::EExpr::Str(e, r, c)), |e, r, c| SyntaxError::Expr(crate::parser::EExpr::Str(e, r, c)),
string_literal::parse() string_literal::parse()
), ),
PackageOrPath::Path
),
map!(
and!( and!(
package_name(), package_name(),
skip_first!(one_or_more!(ascii_char(b' ')), package_version()) skip_first!(one_or_more!(ascii_char(b' ')), package_version())
)
), ),
|answer| { |(name, version)| { PackageOrPath::Package(name, version) }
match answer {
Either::First(str_literal) => PackageOrPath::Path(str_literal),
Either::Second((name, version)) => PackageOrPath::Package(name, version),
}
}
) )
]
} }
fn package_version<'a>() -> impl Parser<'a, Version<'a>, SyntaxError<'a>> { fn package_version<'a>() -> impl Parser<'a, Version<'a>, SyntaxError<'a>> {
@ -300,45 +295,57 @@ fn package_version<'a>() -> impl Parser<'a, Version<'a>, SyntaxError<'a>> {
#[inline(always)] #[inline(always)]
pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, SyntaxError<'a>> { pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, SyntaxError<'a>> {
use encode_unicode::CharExt;
// e.g. rtfeldman/blah // e.g. rtfeldman/blah
// //
// Package names and accounts can be capitalized and can contain dashes. // Package names and accounts can be capitalized and can contain dashes.
// They cannot contain underscores or other special characters. // They cannot contain underscores or other special characters.
// They must be ASCII. // They must be ASCII.
map!( |_, mut state: State<'a>| match chomp_package_part(state.bytes) {
and!( Err(progress) => Err((progress, SyntaxError::ConditionFailed, state)),
parse_package_part, Ok(account) => {
skip_first!(ascii_char(b'/'), parse_package_part) let mut chomped = account.len();
), if let Ok(('/', width)) = char::from_utf8_slice_start(&state.bytes[chomped..]) {
|(account, pkg)| { PackageName { account, pkg } } chomped += width;
) match chomp_package_part(&state.bytes[chomped..]) {
} Err(progress) => Err((progress, SyntaxError::ConditionFailed, state)),
Ok(pkg) => {
chomped += pkg.len();
fn parse_package_part<'a>( state.column += chomped as u16;
arena: &'a Bump, state.bytes = &state.bytes[chomped..];
mut state: State<'a>,
) -> ParseResult<'a, &'a str, SyntaxError<'a>> {
let mut part_buf = String::new_in(arena); // The current "part" (parts are dot-separated.)
while !state.bytes.is_empty() { let value = PackageName { account, pkg };
match peek_utf8_char(&state) { Ok((MadeProgress, value, state))
Ok((ch, bytes_parsed)) => { }
if ch == '-' || ch.is_ascii_alphanumeric() { }
part_buf.push(ch);
state = state.advance_without_indenting(bytes_parsed)?;
} else { } else {
let progress = Progress::progress_when(!part_buf.is_empty()); Err((MadeProgress, SyntaxError::ConditionFailed, state))
return Ok((progress, part_buf.into_bump_str(), state));
} }
} }
Err(reason) => {
let progress = Progress::progress_when(!part_buf.is_empty());
return state.fail(arena, progress, reason);
} }
}
fn chomp_package_part<'a>(buffer: &'a [u8]) -> Result<&'a str, Progress> {
use encode_unicode::CharExt;
let mut chomped = 0;
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
if ch == '-' || ch.is_ascii_alphanumeric() {
chomped += width;
} else {
// we're done
break;
} }
} }
Err(unexpected_eof(arena, state, 0)) if chomped == 0 {
Err(Progress::NoProgress)
} else {
let name = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
Ok(name)
}
} }