mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
start building pattern parser
This commit is contained in:
parent
22b2ab499e
commit
70b5e18c21
3 changed files with 112 additions and 13 deletions
|
@ -13,6 +13,7 @@ use crate::parser::{
|
|||
fail, map, newline_char, not, not_followed_by, optional, sep_by1, then, unexpected,
|
||||
unexpected_eof, Either, ParseResult, Parser, State, SyntaxError,
|
||||
};
|
||||
use crate::pattern::underscore_pattern;
|
||||
use crate::type_annotation;
|
||||
use bumpalo::collections::string::String;
|
||||
use bumpalo::collections::Vec;
|
||||
|
@ -1112,19 +1113,6 @@ fn string_pattern<'a>() -> impl Parser<'a, Pattern<'a>, SyntaxError<'a>> {
|
|||
map!(crate::string_literal::parse(), Pattern::StrLiteral)
|
||||
}
|
||||
|
||||
fn underscore_pattern<'a>() -> impl Parser<'a, Pattern<'a>, SyntaxError<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
let (_, _, next_state) = ascii_char(b'_').parse(arena, state)?;
|
||||
|
||||
let (_, output, final_state) = optional(lowercase_ident()).parse(arena, next_state)?;
|
||||
|
||||
match output {
|
||||
Some(name) => Ok((MadeProgress, Pattern::Underscore(name), final_state)),
|
||||
None => Ok((MadeProgress, Pattern::Underscore(&""), final_state)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_destructure<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, SyntaxError<'a>> {
|
||||
then(
|
||||
collection!(
|
||||
|
|
|
@ -321,6 +321,7 @@ pub enum SyntaxError<'a> {
|
|||
NotYetImplemented(String),
|
||||
TODO,
|
||||
Type(Type<'a>),
|
||||
Pattern(EPattern<'a>),
|
||||
Space(BadInputError),
|
||||
}
|
||||
|
||||
|
@ -368,6 +369,26 @@ impl<'a> SyntaxError<'a> {
|
|||
pub type Row = u32;
|
||||
pub type Col = u16;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EPattern<'a> {
|
||||
Record(PRecord<'a>, Row, Col),
|
||||
Underscore(Row, Col),
|
||||
|
||||
Start(Row, Col),
|
||||
End(Row, Col),
|
||||
Space(BadInputError, Row, Col),
|
||||
FunctionArgument(Row, Col),
|
||||
|
||||
IndentStart(Row, Col),
|
||||
IndentEnd(Row, Col),
|
||||
AsIndentStart(Row, Col),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum PRecord<'a> {
|
||||
EPattern(&'a Type<'a>, Row, Col),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Type<'a> {
|
||||
TRecord(TRecord<'a>, Row, Col),
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
use crate::ast::{
|
||||
AssignedField, Attempting, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation,
|
||||
};
|
||||
use crate::blankspace::{
|
||||
line_comment, space0, space0_after, space0_around, space0_before, space1, space1_around,
|
||||
space1_before, spaces_exactly,
|
||||
};
|
||||
use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
|
||||
use crate::keyword;
|
||||
use crate::number_literal::number_literal;
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
self, allocated, and_then_with_indent_level, ascii_char, ascii_string, attempt, backtrackable,
|
||||
fail, map, newline_char, not, not_followed_by, optional, peek_utf8_char_e, sep_by1, specialize,
|
||||
then, unexpected, unexpected_eof, word1, EPattern, Either, ParseResult, Parser, State,
|
||||
SyntaxError,
|
||||
};
|
||||
use crate::type_annotation;
|
||||
use bumpalo::collections::string::String;
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
|
||||
use roc_region::all::{Located, Region};
|
||||
|
||||
/// Different patterns are supported in different circumstances.
|
||||
/// For example, when branches can pattern match on number literals, but
|
||||
/// assignments and function args can't. Underscore is supported in function
|
||||
|
@ -9,3 +33,69 @@ pub enum PatternType {
|
|||
FunctionArg,
|
||||
WhenBranch,
|
||||
}
|
||||
|
||||
pub fn underscore_pattern<'a>() -> impl Parser<'a, Pattern<'a>, SyntaxError<'a>> {
|
||||
specialize(|e, _, _| SyntaxError::Pattern(e), underscore_pattern_help())
|
||||
}
|
||||
|
||||
fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
let (_, _, next_state) = word1(b'_', EPattern::Underscore).parse(arena, state)?;
|
||||
|
||||
let (_, output, final_state) =
|
||||
optional(|a, s| lowercase_ident_pattern(a, s)).parse(arena, next_state)?;
|
||||
|
||||
match output {
|
||||
Some(name) => Ok((MadeProgress, Pattern::Underscore(name), final_state)),
|
||||
None => Ok((MadeProgress, Pattern::Underscore(&""), final_state)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lowercase_ident_pattern<'a>(
|
||||
arena: &'a Bump,
|
||||
mut state: State<'a>,
|
||||
) -> ParseResult<'a, &'a str, EPattern<'a>> {
|
||||
let mut buf = String::new_in(arena);
|
||||
|
||||
let start_bytes_len = state.bytes.len();
|
||||
|
||||
match peek_utf8_char_e(&state, EPattern::Start, EPattern::Space) {
|
||||
Ok((first_letter, bytes_parsed)) => {
|
||||
// Type variables must start with a lowercase letter.
|
||||
if first_letter.is_alphabetic() && first_letter.is_lowercase() {
|
||||
buf.push(first_letter);
|
||||
} else {
|
||||
return Err((NoProgress, EPattern::Start(state.line, state.column), state));
|
||||
}
|
||||
|
||||
state = state.advance_without_indenting_e(arena, bytes_parsed, EPattern::Space)?;
|
||||
}
|
||||
Err(reason) => return Err((NoProgress, reason, state)),
|
||||
}
|
||||
|
||||
while !state.bytes.is_empty() {
|
||||
match peek_utf8_char_e(&state, EPattern::End, EPattern::Space) {
|
||||
Ok((ch, bytes_parsed)) => {
|
||||
// After the first character, only these are allowed:
|
||||
//
|
||||
// * Unicode alphabetic chars - you might name a variable `鹏` if that's clear to your readers
|
||||
// * ASCII digits - e.g. `1` but not `¾`, both of which pass .is_numeric()
|
||||
if ch.is_alphabetic() || ch.is_ascii_digit() {
|
||||
buf.push(ch);
|
||||
} else {
|
||||
// This must be the end of the type. We're done!
|
||||
break;
|
||||
}
|
||||
|
||||
state = state.advance_without_indenting_e(arena, bytes_parsed, EPattern::Space)?;
|
||||
}
|
||||
Err(reason) => {
|
||||
return state.fail(arena, MadeProgress, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let progress = Progress::from_lengths(start_bytes_len, state.bytes.len());
|
||||
Ok((progress, buf.into_bump_str(), state))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue