mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
pattern number parsing
This commit is contained in:
parent
663ffdeb88
commit
8cff7b060e
4 changed files with 62 additions and 35 deletions
|
@ -225,12 +225,12 @@ fn expr_in_parens_then_equals_help<'a>(
|
|||
let region = loc_expr.region;
|
||||
|
||||
// Re-parse the Expr as a Pattern.
|
||||
let pattern = match expr_to_pattern(arena, &loc_expr.value) {
|
||||
let pattern = match expr_to_pattern_help(arena, &loc_expr.value) {
|
||||
Ok(valid) => valid,
|
||||
Err(fail) => {
|
||||
Err(_) => {
|
||||
return Err((
|
||||
MadeProgress,
|
||||
EExpr::Syntax(arena.alloc(fail), state.line, state.column),
|
||||
EExpr::MalformedPattern(state.line, state.column),
|
||||
state,
|
||||
))
|
||||
}
|
||||
|
@ -485,17 +485,7 @@ fn parse_expr_help<'a>(
|
|||
|
||||
/// If the given Expr would parse the same way as a valid Pattern, convert it.
|
||||
/// Example: (foo) could be either an Expr::Var("foo") or Pattern::Identifier("foo")
|
||||
pub fn expr_to_pattern<'a>(
|
||||
arena: &'a Bump,
|
||||
expr: &Expr<'a>,
|
||||
) -> Result<Pattern<'a>, SyntaxError<'a>> {
|
||||
match expr_to_pattern_help(arena, expr) {
|
||||
Ok(good) => Ok(good),
|
||||
Err(_bad) => Err(SyntaxError::InvalidPattern),
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<'a>, EPattern<'a>> {
|
||||
fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<'a>, ()> {
|
||||
match expr {
|
||||
Expr::Var { module_name, ident } => {
|
||||
if module_name.is_empty() {
|
||||
|
@ -580,10 +570,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::Record {
|
||||
update: Some(_), ..
|
||||
}
|
||||
| Expr::UnaryOp(_, _) => {
|
||||
// TODO nonsense region
|
||||
Err(EPattern::Start(0, 0))
|
||||
}
|
||||
| Expr::UnaryOp(_, _) => Err(()),
|
||||
|
||||
Expr::Str(string) => Ok(Pattern::StrLiteral(string.clone())),
|
||||
Expr::MalformedIdent(string, _problem) => Ok(Pattern::Malformed(string)),
|
||||
|
@ -594,11 +581,11 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
fn assigned_expr_field_to_pattern<'a>(
|
||||
arena: &'a Bump,
|
||||
assigned_field: &AssignedField<'a, Expr<'a>>,
|
||||
) -> Result<Pattern<'a>, SyntaxError<'a>> {
|
||||
) -> Result<Pattern<'a>, ()> {
|
||||
// the assigned fields always store spaces, but this slice is often empty
|
||||
Ok(match assigned_field {
|
||||
AssignedField::RequiredValue(name, spaces, value) => {
|
||||
let pattern = expr_to_pattern(arena, &value.value)?;
|
||||
let pattern = expr_to_pattern_help(arena, &value.value)?;
|
||||
let result = arena.alloc(Located {
|
||||
region: value.region,
|
||||
value: pattern,
|
||||
|
@ -642,7 +629,7 @@ fn assigned_expr_field_to_pattern<'a>(
|
|||
fn assigned_expr_field_to_pattern_help<'a>(
|
||||
arena: &'a Bump,
|
||||
assigned_field: &AssignedField<'a, Expr<'a>>,
|
||||
) -> Result<Pattern<'a>, EPattern<'a>> {
|
||||
) -> Result<Pattern<'a>, ()> {
|
||||
// the assigned fields always store spaces, but this slice is often empty
|
||||
Ok(match assigned_field {
|
||||
AssignedField::RequiredValue(name, spaces, value) => {
|
||||
|
@ -1776,7 +1763,7 @@ fn ident_etc_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
|||
let mut arg_patterns = Vec::with_capacity_in(loc_args.len(), arena);
|
||||
|
||||
for loc_arg in loc_args {
|
||||
match expr_to_pattern(arena, &loc_arg.value) {
|
||||
match expr_to_pattern_help(arena, &loc_arg.value) {
|
||||
Ok(arg_pat) => {
|
||||
arg_patterns.push(Located {
|
||||
value: arg_pat,
|
||||
|
@ -2224,5 +2211,21 @@ fn string_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> {
|
|||
}
|
||||
|
||||
fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> {
|
||||
crate::number_literal::number_literal()
|
||||
map!(crate::number_literal::number_literal(), |literal| {
|
||||
use crate::number_literal::NumLiteral::*;
|
||||
|
||||
match literal {
|
||||
Num(s) => Expr::Num(s),
|
||||
Float(s) => Expr::Float(s),
|
||||
NonBase10Int {
|
||||
string,
|
||||
base,
|
||||
is_negative,
|
||||
} => Expr::NonBase10Int {
|
||||
string,
|
||||
base,
|
||||
is_negative,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
use crate::ast::{Base, Expr};
|
||||
use crate::ast::Base;
|
||||
use crate::parser::{parse_utf8, Number, ParseResult, Parser, Progress, State, SyntaxError};
|
||||
use std::char;
|
||||
use std::str::from_utf8_unchecked;
|
||||
|
||||
pub fn number_literal<'a>() -> impl Parser<'a, Expr<'a>, Number> {
|
||||
pub enum NumLiteral<'a> {
|
||||
Float(&'a str),
|
||||
Num(&'a str),
|
||||
NonBase10Int {
|
||||
string: &'a str,
|
||||
base: Base,
|
||||
is_negative: bool,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> {
|
||||
move |_arena, state: State<'a>| {
|
||||
match state.bytes.get(0) {
|
||||
Some(first_byte) if *first_byte == b'-' => {
|
||||
|
@ -25,7 +35,7 @@ fn parse_number_base<'a>(
|
|||
is_negated: bool,
|
||||
bytes: &'a [u8],
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, Expr<'a>, Number> {
|
||||
) -> ParseResult<'a, NumLiteral<'a>, Number> {
|
||||
match bytes.get(0..2) {
|
||||
Some(b"0b") => chomp_number_base(Base::Binary, is_negated, &bytes[2..], state),
|
||||
Some(b"0o") => chomp_number_base(Base::Octal, is_negated, &bytes[2..], state),
|
||||
|
@ -39,7 +49,7 @@ fn chomp_number_base<'a>(
|
|||
is_negative: bool,
|
||||
bytes: &'a [u8],
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, Expr<'a>, Number> {
|
||||
) -> ParseResult<'a, NumLiteral<'a>, Number> {
|
||||
let (_is_float, chomped) = chomp_number(bytes);
|
||||
|
||||
match parse_utf8(&bytes[0..chomped]) {
|
||||
|
@ -48,7 +58,7 @@ fn chomp_number_base<'a>(
|
|||
// all is well
|
||||
Ok((
|
||||
Progress::MadeProgress,
|
||||
Expr::NonBase10Int {
|
||||
NumLiteral::NonBase10Int {
|
||||
is_negative,
|
||||
string,
|
||||
base,
|
||||
|
@ -71,7 +81,7 @@ fn chomp_number_dec<'a>(
|
|||
is_negative: bool,
|
||||
bytes: &'a [u8],
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, Expr<'a>, Number> {
|
||||
) -> ParseResult<'a, NumLiteral<'a>, Number> {
|
||||
let (is_float, chomped) = chomp_number(bytes);
|
||||
|
||||
if is_negative && chomped == 0 {
|
||||
|
@ -92,9 +102,9 @@ fn chomp_number_dec<'a>(
|
|||
Ok((
|
||||
Progress::MadeProgress,
|
||||
if is_float {
|
||||
Expr::Float(string)
|
||||
NumLiteral::Float(string)
|
||||
} else {
|
||||
Expr::Num(string)
|
||||
NumLiteral::Num(string)
|
||||
},
|
||||
new,
|
||||
))
|
||||
|
|
|
@ -572,6 +572,7 @@ pub enum EPattern<'a> {
|
|||
Space(BadInputError, Row, Col),
|
||||
|
||||
PInParens(PInParens<'a>, Row, Col),
|
||||
NumLiteral(Number, Row, Col),
|
||||
|
||||
IndentStart(Row, Col),
|
||||
IndentEnd(Row, Col),
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::ast::Pattern;
|
||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::ident::{ident, lowercase_ident, Ident};
|
||||
use crate::number_literal::number_literal;
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, optional, specialize, specialize_ref, word1, EPattern, PInParens, PRecord,
|
||||
|
@ -144,9 +143,23 @@ fn loc_pattern_in_parens_help<'a>(
|
|||
|
||||
fn number_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
||||
specialize(
|
||||
|_, r, c| EPattern::Start(r, c),
|
||||
map_with_arena!(number_literal(), |arena, expr| {
|
||||
crate::expr::expr_to_pattern(arena, &expr).unwrap()
|
||||
EPattern::NumLiteral,
|
||||
map!(crate::number_literal::number_literal(), |literal| {
|
||||
use crate::number_literal::NumLiteral::*;
|
||||
|
||||
match literal {
|
||||
Num(s) => Pattern::NumLiteral(s),
|
||||
Float(s) => Pattern::FloatLiteral(s),
|
||||
NonBase10Int {
|
||||
string,
|
||||
base,
|
||||
is_negative,
|
||||
} => Pattern::NonBase10Literal {
|
||||
string,
|
||||
base,
|
||||
is_negative,
|
||||
},
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue