mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Resolve a bunnnch of merge conflicts
This commit is contained in:
commit
6cf755ad8d
705 changed files with 57996 additions and 28320 deletions
|
@ -1,8 +1,10 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use crate::header::{AppHeader, ImportsEntry, InterfaceHeader, PlatformHeader, TypedIdent};
|
||||
use crate::ident::Ident;
|
||||
use bumpalo::collections::String;
|
||||
use bumpalo::collections::{String, Vec};
|
||||
use bumpalo::Bump;
|
||||
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
|
||||
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -95,25 +97,18 @@ pub enum Expr<'a> {
|
|||
SingleQuote(&'a str),
|
||||
|
||||
// Collection Literals
|
||||
List {
|
||||
items: &'a [&'a Loc<Expr<'a>>],
|
||||
final_comments: &'a [CommentOrNewline<'a>],
|
||||
},
|
||||
List(Collection<'a, &'a Loc<Expr<'a>>>),
|
||||
|
||||
RecordUpdate {
|
||||
update: &'a Loc<Expr<'a>>,
|
||||
fields: &'a [Loc<AssignedField<'a, Expr<'a>>>],
|
||||
final_comments: &'a &'a [CommentOrNewline<'a>],
|
||||
fields: Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>,
|
||||
},
|
||||
|
||||
Record {
|
||||
fields: &'a [Loc<AssignedField<'a, Expr<'a>>>],
|
||||
final_comments: &'a [CommentOrNewline<'a>],
|
||||
},
|
||||
Record(Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>),
|
||||
|
||||
// Lookups
|
||||
Var {
|
||||
module_name: &'a str,
|
||||
module_name: &'a str, // module_name will only be filled if the original Roc code stated something like `5 + SomeModule.myVar`, module_name will be blank if it was `5 + myVar`
|
||||
ident: &'a str,
|
||||
},
|
||||
|
||||
|
@ -233,22 +228,23 @@ pub enum TypeAnnotation<'a> {
|
|||
),
|
||||
|
||||
Record {
|
||||
fields: &'a [Loc<AssignedField<'a, TypeAnnotation<'a>>>],
|
||||
fields: Collection<'a, Loc<AssignedField<'a, TypeAnnotation<'a>>>>,
|
||||
/// The row type variable in an open record, e.g. the `r` in `{ name: Str }r`.
|
||||
/// This is None if it's a closed record annotation like `{ name: Str }`.
|
||||
ext: Option<&'a Loc<TypeAnnotation<'a>>>,
|
||||
final_comments: &'a [CommentOrNewline<'a>],
|
||||
},
|
||||
|
||||
/// A tag union, e.g. `[
|
||||
TagUnion {
|
||||
tags: &'a [Loc<Tag<'a>>],
|
||||
/// The row type variable in an open tag union, e.g. the `a` in `[ Foo, Bar ]a`.
|
||||
/// This is None if it's a closed tag union like `[ Foo, Bar]`.
|
||||
ext: Option<&'a Loc<TypeAnnotation<'a>>>,
|
||||
final_comments: &'a [CommentOrNewline<'a>],
|
||||
tags: Collection<'a, Loc<Tag<'a>>>,
|
||||
},
|
||||
|
||||
/// '_', indicating the compiler should infer the type
|
||||
Inferred,
|
||||
|
||||
/// The `*` type variable, e.g. in (List *)
|
||||
Wildcard,
|
||||
|
||||
|
@ -337,10 +333,11 @@ pub enum Pattern<'a> {
|
|||
GlobalTag(&'a str),
|
||||
PrivateTag(&'a str),
|
||||
Apply(&'a Loc<Pattern<'a>>, &'a [Loc<Pattern<'a>>]),
|
||||
|
||||
/// This is Loc<Pattern> rather than Loc<str> so we can record comments
|
||||
/// around the destructured names, e.g. { x ### x does stuff ###, y }
|
||||
/// In practice, these patterns will always be Identifier
|
||||
RecordDestructure(&'a [Loc<Pattern<'a>>]),
|
||||
RecordDestructure(Collection<'a, Loc<Pattern<'a>>>),
|
||||
|
||||
/// A required field pattern, e.g. { x: Just 0 } -> ...
|
||||
/// Can only occur inside of a RecordDestructure
|
||||
|
@ -500,6 +497,126 @@ impl<'a> Pattern<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Collection<'a, T> {
|
||||
pub items: &'a [T],
|
||||
// Use a pointer to a slice (rather than just a slice), in order to avoid bloating
|
||||
// Ast variants. The final_comments field is rarely accessed in the hot path, so
|
||||
// this shouldn't matter much for perf.
|
||||
// Use an Option, so it's possible to initialize without allocating.
|
||||
final_comments: Option<&'a &'a [CommentOrNewline<'a>]>,
|
||||
}
|
||||
|
||||
impl<'a, T> Collection<'a, T> {
|
||||
pub fn empty() -> Collection<'a, T> {
|
||||
Collection {
|
||||
items: &[],
|
||||
final_comments: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_items(items: &'a [T]) -> Collection<'a, T> {
|
||||
Collection {
|
||||
items,
|
||||
final_comments: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_items_and_comments(
|
||||
arena: &'a Bump,
|
||||
items: &'a [T],
|
||||
comments: &'a [CommentOrNewline<'a>],
|
||||
) -> Collection<'a, T> {
|
||||
Collection {
|
||||
items,
|
||||
final_comments: if comments.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(arena.alloc(comments))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_items<V>(&self, new_items: &'a [V]) -> Collection<'a, V> {
|
||||
Collection {
|
||||
items: new_items,
|
||||
final_comments: self.final_comments,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptrify_items(&self, arena: &'a Bump) -> Collection<'a, &'a T> {
|
||||
let mut allocated = Vec::with_capacity_in(self.len(), arena);
|
||||
|
||||
for parsed_elem in self.items {
|
||||
allocated.push(parsed_elem);
|
||||
}
|
||||
|
||||
self.replace_items(allocated.into_bump_slice())
|
||||
}
|
||||
|
||||
pub fn map_items<V: 'a>(&self, arena: &'a Bump, f: impl Fn(&'a T) -> V) -> Collection<'a, V> {
|
||||
let mut allocated = Vec::with_capacity_in(self.len(), arena);
|
||||
|
||||
for parsed_elem in self.items {
|
||||
allocated.push(f(parsed_elem));
|
||||
}
|
||||
|
||||
self.replace_items(allocated.into_bump_slice())
|
||||
}
|
||||
|
||||
pub fn map_items_result<V: 'a, E>(
|
||||
&self,
|
||||
arena: &'a Bump,
|
||||
f: impl Fn(&T) -> Result<V, E>,
|
||||
) -> Result<Collection<'a, V>, E> {
|
||||
let mut allocated = Vec::with_capacity_in(self.len(), arena);
|
||||
|
||||
for parsed_elem in self.items {
|
||||
allocated.push(f(parsed_elem)?);
|
||||
}
|
||||
|
||||
Ok(self.replace_items(allocated.into_bump_slice()))
|
||||
}
|
||||
|
||||
pub fn final_comments(&self) -> &'a [CommentOrNewline<'a>] {
|
||||
if let Some(final_comments) = self.final_comments {
|
||||
*final_comments
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &'a T> {
|
||||
self.items.iter()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.items.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.items.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PartialEq> PartialEq for Collection<'a, T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.items == other.items && self.final_comments() == other.final_comments()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Debug> Debug for Collection<'a, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.final_comments().is_empty() {
|
||||
f.debug_list().entries(self.items.iter()).finish()
|
||||
} else {
|
||||
f.debug_struct("Collection")
|
||||
.field("items", &self.items)
|
||||
.field("final_comments", &self.final_comments())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Spaceable<'a> {
|
||||
fn before(&'a self, _: &'a [CommentOrNewline<'a>]) -> Self;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use crate::ast::CommentOrNewline;
|
||||
use crate::ast::Spaceable;
|
||||
use crate::parser::{
|
||||
self, and, backtrackable, BadInputError, Col, Parser,
|
||||
Progress::{self, *},
|
||||
Row, State,
|
||||
self, and, backtrackable, BadInputError, Col, Parser, Progress::*, Row, State,
|
||||
};
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
|
@ -181,109 +179,6 @@ where
|
|||
spaces_help_help(min_indent, space_problem, indent_problem)
|
||||
}
|
||||
|
||||
pub fn spaces_till_end_of_line<'a, E: 'a>(
|
||||
tab_problem: fn(Row, Col) -> E,
|
||||
) -> impl Parser<'a, Option<&'a str>, E> {
|
||||
move |_, mut state: State<'a>| {
|
||||
let mut bytes = state.bytes;
|
||||
let mut row = state.line;
|
||||
let mut col = state.column;
|
||||
|
||||
for c in bytes {
|
||||
match c {
|
||||
b' ' => {
|
||||
bytes = &bytes[1..];
|
||||
col += 1;
|
||||
}
|
||||
b'\n' => {
|
||||
bytes = &bytes[1..];
|
||||
row += 1;
|
||||
col = 0;
|
||||
|
||||
state.line = row;
|
||||
state.column = col;
|
||||
state.bytes = bytes;
|
||||
|
||||
return Ok((MadeProgress, None, state));
|
||||
}
|
||||
b'\r' => {
|
||||
bytes = &bytes[1..];
|
||||
}
|
||||
b'\t' => {
|
||||
return Err((
|
||||
MadeProgress,
|
||||
tab_problem(row, col),
|
||||
State {
|
||||
line: row,
|
||||
column: col,
|
||||
..state
|
||||
},
|
||||
))
|
||||
}
|
||||
b'#' => match chomp_line_comment(bytes) {
|
||||
Ok(comment) => {
|
||||
state.line += 1;
|
||||
state.column = 0;
|
||||
|
||||
let width = 1 + comment.len();
|
||||
if let Some(b'\n') = bytes.get(width) {
|
||||
state.bytes = &bytes[width + 1..];
|
||||
} else {
|
||||
state.bytes = &bytes[width..];
|
||||
}
|
||||
|
||||
return Ok((MadeProgress, Some(comment), state));
|
||||
}
|
||||
Err(_) => unreachable!("we check the first character is a #"),
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
if state.column == col {
|
||||
Ok((NoProgress, None, state))
|
||||
} else {
|
||||
Ok((
|
||||
MadeProgress,
|
||||
None,
|
||||
State {
|
||||
column: col,
|
||||
bytes,
|
||||
..state
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn chomp_line_comment(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
if let Some(b'#') = buffer.get(0) {
|
||||
if (&buffer[1..]).starts_with(b"# ") {
|
||||
// this is a doc comment, not a line comment
|
||||
Err(NoProgress)
|
||||
} else {
|
||||
use encode_unicode::CharExt;
|
||||
|
||||
let mut chomped = 1;
|
||||
|
||||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if ch == '\n' {
|
||||
break;
|
||||
} else {
|
||||
chomped += width;
|
||||
}
|
||||
}
|
||||
|
||||
let comment_bytes = &buffer[1..chomped];
|
||||
let comment = unsafe { std::str::from_utf8_unchecked(comment_bytes) };
|
||||
|
||||
Ok(comment)
|
||||
}
|
||||
} else {
|
||||
Err(NoProgress)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn spaces_help_help<'a, E>(
|
||||
min_indent: u16,
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
use crate::ast::{AssignedField, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation};
|
||||
use crate::ast::{
|
||||
AssignedField, Collection, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation,
|
||||
};
|
||||
use crate::blankspace::{space0_after_e, space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
self, backtrackable, optional, sep_by1, sep_by1_e, specialize, specialize_ref, then,
|
||||
trailing_sep_by0, word1, word2, EExpr, EInParens, ELambda, EPattern, ERecord, EString, Either,
|
||||
Expect, If, List, Number, ParseResult, Parser, State, Type, When,
|
||||
trailing_sep_by0, word1, word2, EExpect, EExpr, EIf, EInParens, ELambda, EList, ENumber,
|
||||
EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, Parser, State,
|
||||
};
|
||||
use crate::pattern::loc_closure_param;
|
||||
use crate::type_annotation;
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
|
||||
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
||||
use roc_region::all::{Located, Position, Region};
|
||||
|
||||
use crate::parser::Progress::{self, *};
|
||||
|
@ -803,7 +805,7 @@ fn parse_defs_end<'a>(
|
|||
Err((NoProgress, _, _)) => {
|
||||
let start = state.get_position();
|
||||
|
||||
match crate::parser::keyword_e(crate::keyword::EXPECT, Expect::Expect)
|
||||
match crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect)
|
||||
.parse(arena, state)
|
||||
{
|
||||
Err((_, _, _)) => {
|
||||
|
@ -863,8 +865,8 @@ fn parse_defs_end<'a>(
|
|||
space0_before_e(
|
||||
type_annotation::located_help(min_indent + 1),
|
||||
min_indent + 1,
|
||||
Type::TSpace,
|
||||
Type::TIndentStart,
|
||||
EType::TSpace,
|
||||
EType::TIndentStart,
|
||||
),
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
@ -1101,8 +1103,8 @@ fn parse_expr_operator<'a>(
|
|||
space0_before_e(
|
||||
type_annotation::located_help(indented_more),
|
||||
min_indent,
|
||||
Type::TSpace,
|
||||
Type::TIndentStart,
|
||||
EType::TSpace,
|
||||
EType::TIndentStart,
|
||||
),
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
@ -1128,8 +1130,8 @@ fn parse_expr_operator<'a>(
|
|||
space0_before_e(
|
||||
type_annotation::located_help(indented_more),
|
||||
min_indent,
|
||||
Type::TSpace,
|
||||
Type::TIndentStart,
|
||||
EType::TSpace,
|
||||
EType::TIndentStart,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -1448,20 +1450,14 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
|
||||
Expr::ParensAround(sub_expr) => expr_to_pattern_help(arena, sub_expr),
|
||||
|
||||
Expr::Record {
|
||||
fields,
|
||||
final_comments: _,
|
||||
} => {
|
||||
let mut loc_patterns = Vec::with_capacity_in(fields.len(), arena);
|
||||
|
||||
for loc_assigned_field in fields.iter() {
|
||||
Expr::Record(fields) => {
|
||||
let patterns = fields.map_items_result(arena, |loc_assigned_field| {
|
||||
let region = loc_assigned_field.region;
|
||||
let value = assigned_expr_field_to_pattern_help(arena, &loc_assigned_field.value)?;
|
||||
Ok(Located { region, value })
|
||||
})?;
|
||||
|
||||
loc_patterns.push(Located { region, value });
|
||||
}
|
||||
|
||||
Ok(Pattern::RecordDestructure(loc_patterns.into_bump_slice()))
|
||||
Ok(Pattern::RecordDestructure(patterns))
|
||||
}
|
||||
|
||||
Expr::Float(string) => Ok(Pattern::FloatLiteral(string)),
|
||||
|
@ -1654,21 +1650,21 @@ mod when {
|
|||
pub fn expr_help<'a>(
|
||||
min_indent: u16,
|
||||
options: ExprParseOptions,
|
||||
) -> impl Parser<'a, Expr<'a>, When<'a>> {
|
||||
) -> impl Parser<'a, Expr<'a>, EWhen<'a>> {
|
||||
then(
|
||||
and!(
|
||||
when_with_indent(),
|
||||
skip_second!(
|
||||
space0_around_ee(
|
||||
specialize_ref(When::Condition, move |arena, state| {
|
||||
specialize_ref(EWhen::Condition, move |arena, state| {
|
||||
parse_loc_expr_with_options(min_indent, options, arena, state)
|
||||
}),
|
||||
min_indent,
|
||||
When::Space,
|
||||
When::IndentCondition,
|
||||
When::IndentIs,
|
||||
EWhen::Space,
|
||||
EWhen::IndentCondition,
|
||||
EWhen::IndentIs,
|
||||
),
|
||||
parser::keyword_e(keyword::IS, When::Is)
|
||||
parser::keyword_e(keyword::IS, EWhen::Is)
|
||||
)
|
||||
),
|
||||
move |arena, state, progress, (case_indent, loc_condition)| {
|
||||
|
@ -1676,7 +1672,7 @@ mod when {
|
|||
return Err((
|
||||
progress,
|
||||
// TODO maybe pass case_indent here?
|
||||
When::PatternAlignment(5, state.line, state.column),
|
||||
EWhen::PatternAlignment(5, state.line, state.column),
|
||||
state,
|
||||
));
|
||||
}
|
||||
|
@ -1696,9 +1692,9 @@ mod when {
|
|||
}
|
||||
|
||||
/// Parsing when with indentation.
|
||||
fn when_with_indent<'a>() -> impl Parser<'a, u16, When<'a>> {
|
||||
fn when_with_indent<'a>() -> impl Parser<'a, u16, EWhen<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
parser::keyword_e(keyword::WHEN, When::When)
|
||||
parser::keyword_e(keyword::WHEN, EWhen::When)
|
||||
.parse(arena, state)
|
||||
.map(|(progress, (), state)| (progress, state.indent_col, state))
|
||||
}
|
||||
|
@ -1707,7 +1703,7 @@ mod when {
|
|||
fn branches<'a>(
|
||||
min_indent: u16,
|
||||
options: ExprParseOptions,
|
||||
) -> impl Parser<'a, Vec<'a, &'a WhenBranch<'a>>, When<'a>> {
|
||||
) -> impl Parser<'a, Vec<'a, &'a WhenBranch<'a>>, EWhen<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let when_indent = state.indent_col;
|
||||
|
||||
|
@ -1744,7 +1740,7 @@ mod when {
|
|||
let indent = pattern_indent_level - indent_col;
|
||||
Err((
|
||||
MadeProgress,
|
||||
When::PatternAlignment(indent, state.line, state.column),
|
||||
EWhen::PatternAlignment(indent, state.line, state.column),
|
||||
state,
|
||||
))
|
||||
}
|
||||
|
@ -1802,7 +1798,7 @@ mod when {
|
|||
(Col, Vec<'a, Located<Pattern<'a>>>),
|
||||
Option<Located<Expr<'a>>>,
|
||||
),
|
||||
When<'a>,
|
||||
EWhen<'a>,
|
||||
> {
|
||||
let options = ExprParseOptions {
|
||||
check_for_arrow: false,
|
||||
|
@ -1813,16 +1809,16 @@ mod when {
|
|||
one_of![
|
||||
map!(
|
||||
skip_first!(
|
||||
parser::keyword_e(keyword::IF, When::IfToken),
|
||||
parser::keyword_e(keyword::IF, EWhen::IfToken),
|
||||
// TODO we should require space before the expression but not after
|
||||
space0_around_ee(
|
||||
specialize_ref(When::IfGuard, move |arena, state| {
|
||||
specialize_ref(EWhen::IfGuard, move |arena, state| {
|
||||
parse_loc_expr_with_options(min_indent + 1, options, arena, state)
|
||||
}),
|
||||
min_indent,
|
||||
When::Space,
|
||||
When::IndentIfGuard,
|
||||
When::IndentArrow,
|
||||
EWhen::Space,
|
||||
EWhen::IndentIfGuard,
|
||||
EWhen::IndentArrow,
|
||||
)
|
||||
),
|
||||
Some
|
||||
|
@ -1834,17 +1830,17 @@ mod when {
|
|||
|
||||
fn branch_single_alternative<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Located<Pattern<'a>>, When<'a>> {
|
||||
) -> impl Parser<'a, Located<Pattern<'a>>, EWhen<'a>> {
|
||||
move |arena, state| {
|
||||
let (_, spaces, state) =
|
||||
backtrackable(space0_e(min_indent, When::Space, When::IndentPattern))
|
||||
backtrackable(space0_e(min_indent, EWhen::Space, EWhen::IndentPattern))
|
||||
.parse(arena, state)?;
|
||||
|
||||
let (_, loc_pattern, state) = space0_after_e(
|
||||
specialize(When::Pattern, crate::pattern::loc_pattern_help(min_indent)),
|
||||
specialize(EWhen::Pattern, crate::pattern::loc_pattern_help(min_indent)),
|
||||
min_indent,
|
||||
When::Space,
|
||||
When::IndentPattern,
|
||||
EWhen::Space,
|
||||
EWhen::IndentPattern,
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
|
@ -1865,12 +1861,12 @@ mod when {
|
|||
fn branch_alternatives_help<'a>(
|
||||
min_indent: u16,
|
||||
pattern_indent_level: Option<u16>,
|
||||
) -> impl Parser<'a, (Col, Vec<'a, Located<Pattern<'a>>>), When<'a>> {
|
||||
) -> impl Parser<'a, (Col, Vec<'a, Located<Pattern<'a>>>), EWhen<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let initial = state;
|
||||
|
||||
// put no restrictions on the indent after the spaces; we'll check it manually
|
||||
match space0_e(0, When::Space, When::IndentPattern).parse(arena, state) {
|
||||
match space0_e(0, EWhen::Space, EWhen::IndentPattern).parse(arena, state) {
|
||||
Err((MadeProgress, fail, _)) => Err((NoProgress, fail, initial)),
|
||||
Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)),
|
||||
Ok((_progress, spaces, state)) => {
|
||||
|
@ -1879,7 +1875,7 @@ mod when {
|
|||
// this branch is indented too much
|
||||
Err((
|
||||
NoProgress,
|
||||
When::IndentPattern(state.line, state.column),
|
||||
EWhen::IndentPattern(state.line, state.column),
|
||||
initial,
|
||||
))
|
||||
}
|
||||
|
@ -1887,7 +1883,7 @@ mod when {
|
|||
let indent = wanted - state.column;
|
||||
Err((
|
||||
NoProgress,
|
||||
When::PatternAlignment(indent, state.line, state.column),
|
||||
EWhen::PatternAlignment(indent, state.line, state.column),
|
||||
initial,
|
||||
))
|
||||
}
|
||||
|
@ -1899,7 +1895,7 @@ mod when {
|
|||
let pattern_indent_col = state.column;
|
||||
|
||||
let parser = sep_by1(
|
||||
word1(b'|', When::Bar),
|
||||
word1(b'|', EWhen::Bar),
|
||||
branch_single_alternative(pattern_indent + 1),
|
||||
);
|
||||
|
||||
|
@ -1933,16 +1929,16 @@ mod when {
|
|||
}
|
||||
|
||||
/// Parsing the righthandside of a branch in a when conditional.
|
||||
fn branch_result<'a>(indent: u16) -> impl Parser<'a, Located<Expr<'a>>, When<'a>> {
|
||||
fn branch_result<'a>(indent: u16) -> impl Parser<'a, Located<Expr<'a>>, EWhen<'a>> {
|
||||
skip_first!(
|
||||
word2(b'-', b'>', When::Arrow),
|
||||
word2(b'-', b'>', EWhen::Arrow),
|
||||
space0_before_e(
|
||||
specialize_ref(When::Branch, move |arena, state| parse_loc_expr(
|
||||
specialize_ref(EWhen::Branch, move |arena, state| parse_loc_expr(
|
||||
indent, arena, state
|
||||
)),
|
||||
indent,
|
||||
When::Space,
|
||||
When::IndentBranch,
|
||||
EWhen::Space,
|
||||
EWhen::IndentBranch,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -1950,38 +1946,38 @@ mod when {
|
|||
|
||||
fn if_branch<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, (Located<Expr<'a>>, Located<Expr<'a>>), If<'a>> {
|
||||
) -> impl Parser<'a, (Located<Expr<'a>>, Located<Expr<'a>>), EIf<'a>> {
|
||||
move |arena, state| {
|
||||
// NOTE: only parse spaces before the expression
|
||||
let (_, cond, state) = space0_around_ee(
|
||||
specialize_ref(If::Condition, move |arena, state| {
|
||||
specialize_ref(EIf::Condition, move |arena, state| {
|
||||
parse_loc_expr(min_indent, arena, state)
|
||||
}),
|
||||
min_indent,
|
||||
If::Space,
|
||||
If::IndentCondition,
|
||||
If::IndentThenToken,
|
||||
EIf::Space,
|
||||
EIf::IndentCondition,
|
||||
EIf::IndentThenToken,
|
||||
)
|
||||
.parse(arena, state)
|
||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||
|
||||
let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then)
|
||||
let (_, _, state) = parser::keyword_e(keyword::THEN, EIf::Then)
|
||||
.parse(arena, state)
|
||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||
|
||||
let (_, then_branch, state) = space0_around_ee(
|
||||
specialize_ref(If::ThenBranch, move |arena, state| {
|
||||
specialize_ref(EIf::ThenBranch, move |arena, state| {
|
||||
parse_loc_expr(min_indent, arena, state)
|
||||
}),
|
||||
min_indent,
|
||||
If::Space,
|
||||
If::IndentThenBranch,
|
||||
If::IndentElseToken,
|
||||
EIf::Space,
|
||||
EIf::IndentThenBranch,
|
||||
EIf::IndentElseToken,
|
||||
)
|
||||
.parse(arena, state)
|
||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||
|
||||
let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else)
|
||||
let (_, _, state) = parser::keyword_e(keyword::ELSE, EIf::Else)
|
||||
.parse(arena, state)
|
||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||
|
||||
|
@ -1992,26 +1988,26 @@ fn if_branch<'a>(
|
|||
fn expect_help<'a>(
|
||||
min_indent: u16,
|
||||
options: ExprParseOptions,
|
||||
) -> impl Parser<'a, Expr<'a>, Expect<'a>> {
|
||||
) -> impl Parser<'a, Expr<'a>, EExpect<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
let start = state.get_position();
|
||||
|
||||
let (_, _, state) =
|
||||
parser::keyword_e(keyword::EXPECT, Expect::Expect).parse(arena, state)?;
|
||||
parser::keyword_e(keyword::EXPECT, EExpect::Expect).parse(arena, state)?;
|
||||
|
||||
let (_, condition, state) = space0_before_e(
|
||||
specialize_ref(Expect::Condition, move |arena, state| {
|
||||
specialize_ref(EExpect::Condition, move |arena, state| {
|
||||
parse_loc_expr_with_options(start.col + 1, options, arena, state)
|
||||
}),
|
||||
start.col + 1,
|
||||
Expect::Space,
|
||||
Expect::IndentCondition,
|
||||
EExpect::Space,
|
||||
EExpect::IndentCondition,
|
||||
)
|
||||
.parse(arena, state)
|
||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||
|
||||
let parse_cont = specialize_ref(
|
||||
Expect::Continuation,
|
||||
EExpect::Continuation,
|
||||
space0_before_e(
|
||||
move |a, s| parse_loc_expr(min_indent, a, s),
|
||||
min_indent,
|
||||
|
@ -2031,9 +2027,9 @@ fn expect_help<'a>(
|
|||
fn if_expr_help<'a>(
|
||||
min_indent: u16,
|
||||
options: ExprParseOptions,
|
||||
) -> impl Parser<'a, Expr<'a>, If<'a>> {
|
||||
) -> impl Parser<'a, Expr<'a>, EIf<'a>> {
|
||||
move |arena: &'a Bump, state| {
|
||||
let (_, _, state) = parser::keyword_e(keyword::IF, If::If).parse(arena, state)?;
|
||||
let (_, _, state) = parser::keyword_e(keyword::IF, EIf::If).parse(arena, state)?;
|
||||
|
||||
let mut branches = Vec::with_capacity_in(1, arena);
|
||||
|
||||
|
@ -2047,8 +2043,8 @@ fn if_expr_help<'a>(
|
|||
// try to parse another `if`
|
||||
// NOTE this drops spaces between the `else` and the `if`
|
||||
let optional_if = and!(
|
||||
backtrackable(space0_e(min_indent, If::Space, If::IndentIf)),
|
||||
parser::keyword_e(keyword::IF, If::If)
|
||||
backtrackable(space0_e(min_indent, EIf::Space, EIf::IndentIf)),
|
||||
parser::keyword_e(keyword::IF, EIf::If)
|
||||
);
|
||||
|
||||
match optional_if.parse(arena, state) {
|
||||
|
@ -2061,12 +2057,12 @@ fn if_expr_help<'a>(
|
|||
};
|
||||
|
||||
let (_, else_branch, state) = space0_before_e(
|
||||
specialize_ref(If::ElseBranch, move |arena, state| {
|
||||
specialize_ref(EIf::ElseBranch, move |arena, state| {
|
||||
parse_loc_expr_with_options(min_indent, options, arena, state)
|
||||
}),
|
||||
min_indent,
|
||||
If::Space,
|
||||
If::IndentElseBranch,
|
||||
EIf::Space,
|
||||
EIf::IndentElseBranch,
|
||||
)
|
||||
.parse(arena, state_final_else)
|
||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||
|
@ -2150,32 +2146,26 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>> {
|
||||
fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EList<'a>> {
|
||||
move |arena, state| {
|
||||
let (_, (parsed_elems, final_comments), state) = collection_trailing_sep_e!(
|
||||
word1(b'[', List::Open),
|
||||
specialize_ref(List::Expr, move |a, s| parse_loc_expr_no_multi_backpassing(
|
||||
min_indent, a, s
|
||||
)),
|
||||
word1(b',', List::End),
|
||||
word1(b']', List::End),
|
||||
let (_, elements, state) = collection_trailing_sep_e!(
|
||||
word1(b'[', EList::Open),
|
||||
specialize_ref(
|
||||
EList::Expr,
|
||||
move |a, s| parse_loc_expr_no_multi_backpassing(min_indent, a, s)
|
||||
),
|
||||
word1(b',', EList::End),
|
||||
word1(b']', EList::End),
|
||||
min_indent,
|
||||
List::Open,
|
||||
List::Space,
|
||||
List::IndentEnd
|
||||
EList::Open,
|
||||
EList::Space,
|
||||
EList::IndentEnd,
|
||||
Expr::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
let mut allocated = Vec::with_capacity_in(parsed_elems.len(), arena);
|
||||
|
||||
for parsed_elem in parsed_elems {
|
||||
allocated.push(&*arena.alloc(parsed_elem));
|
||||
}
|
||||
|
||||
let expr = Expr::List {
|
||||
items: allocated.into_bump_slice(),
|
||||
final_comments,
|
||||
};
|
||||
let elements = elements.ptrify_items(arena);
|
||||
let expr = Expr::List(elements);
|
||||
|
||||
Ok((MadeProgress, expr, state))
|
||||
}
|
||||
|
@ -2313,13 +2303,17 @@ fn record_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EExpr<'
|
|||
let mut value = match opt_update {
|
||||
Some(update) => Expr::RecordUpdate {
|
||||
update: &*arena.alloc(update),
|
||||
fields: loc_assigned_fields_with_comments.value.0.into_bump_slice(),
|
||||
final_comments: arena.alloc(loc_assigned_fields_with_comments.value.1),
|
||||
},
|
||||
None => Expr::Record {
|
||||
fields: loc_assigned_fields_with_comments.value.0.into_bump_slice(),
|
||||
final_comments: loc_assigned_fields_with_comments.value.1,
|
||||
fields: Collection::with_items_and_comments(
|
||||
arena,
|
||||
loc_assigned_fields_with_comments.value.0.into_bump_slice(),
|
||||
arena.alloc(loc_assigned_fields_with_comments.value.1),
|
||||
),
|
||||
},
|
||||
None => Expr::Record(Collection::with_items_and_comments(
|
||||
arena,
|
||||
loc_assigned_fields_with_comments.value.0.into_bump_slice(),
|
||||
loc_assigned_fields_with_comments.value.1,
|
||||
)),
|
||||
};
|
||||
|
||||
// there can be field access, e.g. `{ x : 4 }.x`
|
||||
|
@ -2350,7 +2344,7 @@ fn single_quote_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> {
|
|||
)
|
||||
}
|
||||
|
||||
fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> {
|
||||
fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
|
||||
map!(
|
||||
crate::number_literal::positive_number_literal(),
|
||||
|literal| {
|
||||
|
@ -2373,7 +2367,7 @@ fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> {
|
|||
)
|
||||
}
|
||||
|
||||
fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> {
|
||||
fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
|
||||
map!(crate::number_literal::number_literal(), |literal| {
|
||||
use crate::number_literal::NumLiteral::*;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ast::{CommentOrNewline, Spaceable, StrLiteral, TypeAnnotation};
|
||||
use crate::ast::{Collection, CommentOrNewline, Spaceable, StrLiteral, TypeAnnotation};
|
||||
use crate::blankspace::space0_e;
|
||||
use crate::ident::lowercase_ident;
|
||||
use crate::parser::Progress::{self, *};
|
||||
|
@ -9,13 +9,13 @@ use crate::string_literal;
|
|||
use bumpalo::collections::Vec;
|
||||
use roc_region::all::Loc;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct PackageName<'a> {
|
||||
pub account: &'a str,
|
||||
pub pkg: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum Version<'a> {
|
||||
Exact(&'a str),
|
||||
Range {
|
||||
|
@ -32,13 +32,13 @@ pub enum VersionComparison {
|
|||
DisallowsEqual,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum PackageOrPath<'a> {
|
||||
Package(PackageName<'a>, Version<'a>),
|
||||
Path(StrLiteral<'a>),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct ModuleName<'a>(&'a str);
|
||||
|
||||
impl<'a> From<ModuleName<'a>> for &'a str {
|
||||
|
@ -60,8 +60,8 @@ impl<'a> ModuleName<'a> {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct InterfaceHeader<'a> {
|
||||
pub name: Loc<ModuleName<'a>>,
|
||||
pub exposes: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub exposes: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>,
|
||||
|
||||
// Potential comments and newlines - these will typically all be empty.
|
||||
pub before_header: &'a [CommentOrNewline<'a>],
|
||||
|
@ -72,7 +72,7 @@ pub struct InterfaceHeader<'a> {
|
|||
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum To<'a> {
|
||||
ExistingPackage(&'a str),
|
||||
NewPackage(PackageOrPath<'a>),
|
||||
|
@ -81,9 +81,9 @@ pub enum To<'a> {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct AppHeader<'a> {
|
||||
pub name: Loc<StrLiteral<'a>>,
|
||||
pub packages: Vec<'a, Loc<PackageEntry<'a>>>,
|
||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub packages: Collection<'a, Loc<PackageEntry<'a>>>,
|
||||
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub to: Loc<To<'a>>,
|
||||
|
||||
// Potential comments and newlines - these will typically all be empty.
|
||||
|
@ -117,7 +117,7 @@ pub struct PackageHeader<'a> {
|
|||
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum PlatformRigid<'a> {
|
||||
Entry { rigid: &'a str, alias: &'a str },
|
||||
|
||||
|
@ -137,7 +137,7 @@ impl<'a> Spaceable<'a> for PlatformRigid<'a> {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PlatformRequires<'a> {
|
||||
pub rigids: Vec<'a, Loc<PlatformRigid<'a>>>,
|
||||
pub rigids: Collection<'a, Loc<PlatformRigid<'a>>>,
|
||||
pub signature: Loc<TypedIdent<'a>>,
|
||||
}
|
||||
|
||||
|
@ -145,10 +145,10 @@ pub struct PlatformRequires<'a> {
|
|||
pub struct PlatformHeader<'a> {
|
||||
pub name: Loc<PackageName<'a>>,
|
||||
pub requires: PlatformRequires<'a>,
|
||||
pub exposes: Vec<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
pub packages: Vec<'a, Loc<PackageEntry<'a>>>,
|
||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub exposes: Collection<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
pub packages: Collection<'a, Loc<PackageEntry<'a>>>,
|
||||
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub effects: Effects<'a>,
|
||||
|
||||
// Potential comments and newlines - these will typically all be empty.
|
||||
|
@ -174,10 +174,10 @@ pub struct Effects<'a> {
|
|||
pub spaces_after_type_name: &'a [CommentOrNewline<'a>],
|
||||
pub effect_shortname: &'a str,
|
||||
pub effect_type_name: &'a str,
|
||||
pub entries: &'a [Loc<TypedIdent<'a>>],
|
||||
pub entries: Collection<'a, Loc<TypedIdent<'a>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ExposesEntry<'a, T> {
|
||||
/// e.g. `Task`
|
||||
Exposed(T),
|
||||
|
@ -196,16 +196,19 @@ impl<'a, T> Spaceable<'a> for ExposesEntry<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ImportsEntry<'a> {
|
||||
/// e.g. `Task` or `Task.{ Task, after }`
|
||||
Module(ModuleName<'a>, Vec<'a, Loc<ExposesEntry<'a, &'a str>>>),
|
||||
Module(
|
||||
ModuleName<'a>,
|
||||
Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
|
||||
/// e.g. `base.Task` or `base.Task.{ after }` or `base.{ Task.{ Task, after } }`
|
||||
Package(
|
||||
&'a str,
|
||||
ModuleName<'a>,
|
||||
Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
|
||||
// Spaces
|
||||
|
@ -224,7 +227,7 @@ impl<'a> ExposesEntry<'a, &'a str> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum TypedIdent<'a> {
|
||||
/// e.g.
|
||||
///
|
||||
|
@ -240,7 +243,7 @@ pub enum TypedIdent<'a> {
|
|||
SpaceAfter(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum PackageEntry<'a> {
|
||||
Entry {
|
||||
shorthand: &'a str,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ast::{CommentOrNewline, Def, Module};
|
||||
use crate::ast::{Collection, CommentOrNewline, Def, Module};
|
||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::header::{
|
||||
package_entry, package_name, package_or_path, AppHeader, Effects, ExposesEntry, ImportsEntry,
|
||||
|
@ -32,7 +32,7 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn module_defs<'a>() -> impl Parser<'a, Vec<'a, Located<Def<'a>>>, SyntaxError<'a>> {
|
||||
// force that we pare until the end of the input
|
||||
// force that we parse until the end of the input
|
||||
let min_indent = 0;
|
||||
skip_second!(
|
||||
specialize(
|
||||
|
@ -203,7 +203,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
|||
let (_, provides, state) =
|
||||
specialize(EHeader::Provides, provides_to()).parse(arena, state)?;
|
||||
|
||||
let (before_packages, after_packages, package_entries) = match opt_pkgs {
|
||||
let (before_packages, after_packages, packages) = match opt_pkgs {
|
||||
Some(pkgs) => {
|
||||
let pkgs: Packages<'a> = pkgs; // rustc must be told the type here
|
||||
|
||||
|
@ -213,23 +213,23 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
|||
pkgs.entries,
|
||||
)
|
||||
}
|
||||
None => (&[] as _, &[] as _, Vec::new_in(arena)),
|
||||
None => (&[] as _, &[] as _, Collection::empty()),
|
||||
};
|
||||
|
||||
// rustc must be told the type here
|
||||
#[allow(clippy::type_complexity)]
|
||||
let opt_imports: Option<(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ImportsEntry<'a>>>,
|
||||
Collection<'a, Located<ImportsEntry<'a>>>,
|
||||
)> = opt_imports;
|
||||
|
||||
let ((before_imports, after_imports), imports) =
|
||||
opt_imports.unwrap_or_else(|| ((&[] as _, &[] as _), Vec::new_in(arena)));
|
||||
opt_imports.unwrap_or_else(|| ((&[] as _, &[] as _), Collection::empty()));
|
||||
let provides: ProvidesTo<'a> = provides; // rustc must be told the type here
|
||||
|
||||
let header = AppHeader {
|
||||
name,
|
||||
packages: package_entries,
|
||||
packages,
|
||||
imports,
|
||||
provides: provides.entries,
|
||||
to: provides.to,
|
||||
|
@ -303,7 +303,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
|||
|
||||
#[derive(Debug)]
|
||||
struct ProvidesTo<'a> {
|
||||
entries: Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
entries: Collection<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
to: Located<To<'a>>,
|
||||
|
||||
before_provides_keyword: &'a [CommentOrNewline<'a>],
|
||||
|
@ -362,7 +362,7 @@ fn provides_without_to<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
Collection<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
EProvides<'a>,
|
||||
> {
|
||||
|
@ -376,14 +376,16 @@ fn provides_without_to<'a>() -> impl Parser<
|
|||
EProvides::IndentProvides,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EProvides::ListStart),
|
||||
exposes_entry(EProvides::Identifier),
|
||||
word1(b',', EProvides::ListEnd),
|
||||
word1(b']', EProvides::ListEnd),
|
||||
min_indent,
|
||||
EProvides::Open,
|
||||
EProvides::Space,
|
||||
EProvides::IndentListEnd
|
||||
EProvides::IndentListEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -442,15 +444,17 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a
|
|||
#[inline(always)]
|
||||
fn requires_rigids<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Vec<'a, Located<PlatformRigid<'a>>>, ERequires<'a>> {
|
||||
collection_e!(
|
||||
) -> impl Parser<'a, Collection<'a, Located<PlatformRigid<'a>>>, ERequires<'a>> {
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
specialize(|_, r, c| ERequires::Rigid(r, c), loc!(requires_rigid())),
|
||||
word1(b',', ERequires::ListEnd),
|
||||
word1(b'}', ERequires::ListEnd),
|
||||
min_indent,
|
||||
ERequires::Open,
|
||||
ERequires::Space,
|
||||
ERequires::IndentListEnd
|
||||
ERequires::IndentListEnd,
|
||||
PlatformRigid::SpaceBefore
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -487,7 +491,7 @@ fn exposes_values<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
Collection<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
EExposes,
|
||||
> {
|
||||
|
@ -502,14 +506,16 @@ fn exposes_values<'a>() -> impl Parser<
|
|||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EExposes::ListStart),
|
||||
exposes_entry(EExposes::Identifier),
|
||||
word1(b',', EExposes::ListEnd),
|
||||
word1(b']', EExposes::ListEnd),
|
||||
min_indent,
|
||||
EExposes::Open,
|
||||
EExposes::Space,
|
||||
EExposes::IndentListEnd
|
||||
EExposes::IndentListEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -539,7 +545,7 @@ fn exposes_modules<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
Collection<'a, Located<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
),
|
||||
EExposes,
|
||||
> {
|
||||
|
@ -554,14 +560,16 @@ fn exposes_modules<'a>() -> impl Parser<
|
|||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EExposes::ListStart),
|
||||
exposes_module(EExposes::Identifier),
|
||||
word1(b',', EExposes::ListEnd),
|
||||
word1(b']', EExposes::ListEnd),
|
||||
min_indent,
|
||||
EExposes::Open,
|
||||
EExposes::Space,
|
||||
EExposes::IndentListEnd
|
||||
EExposes::IndentListEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -582,8 +590,7 @@ where
|
|||
|
||||
#[derive(Debug)]
|
||||
struct Packages<'a> {
|
||||
entries: Vec<'a, Located<PackageEntry<'a>>>,
|
||||
|
||||
entries: Collection<'a, Located<PackageEntry<'a>>>,
|
||||
before_packages_keyword: &'a [CommentOrNewline<'a>],
|
||||
after_packages_keyword: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
@ -602,17 +609,22 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
|
|||
EPackages::IndentPackages,
|
||||
EPackages::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', EPackages::ListStart),
|
||||
specialize(EPackages::PackageEntry, loc!(package_entry())),
|
||||
word1(b',', EPackages::ListEnd),
|
||||
word1(b'}', EPackages::ListEnd),
|
||||
min_indent,
|
||||
EPackages::Open,
|
||||
EPackages::Space,
|
||||
EPackages::IndentListEnd
|
||||
EPackages::IndentListEnd,
|
||||
PackageEntry::SpaceBefore
|
||||
)
|
||||
),
|
||||
|((before_packages_keyword, after_packages_keyword), entries)| {
|
||||
|((before_packages_keyword, after_packages_keyword), entries): (
|
||||
(_, _),
|
||||
Collection<'a, _>
|
||||
)| {
|
||||
Packages {
|
||||
entries,
|
||||
before_packages_keyword,
|
||||
|
@ -627,7 +639,7 @@ fn imports<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ImportsEntry<'a>>>,
|
||||
Collection<'a, Located<ImportsEntry<'a>>>,
|
||||
),
|
||||
EImports,
|
||||
> {
|
||||
|
@ -642,14 +654,16 @@ fn imports<'a>() -> impl Parser<
|
|||
EImports::IndentImports,
|
||||
EImports::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EImports::ListStart),
|
||||
loc!(imports_entry()),
|
||||
word1(b',', EImports::ListEnd),
|
||||
word1(b']', EImports::ListEnd),
|
||||
min_indent,
|
||||
EImports::Open,
|
||||
EImports::Space,
|
||||
EImports::IndentListEnd
|
||||
EImports::IndentListEnd,
|
||||
ImportsEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -683,14 +697,16 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
|
|||
space0_e(min_indent, EEffects::Space, EEffects::IndentListStart)
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
let (_, entries, state) = collection_e!(
|
||||
let (_, entries, state) = collection_trailing_sep_e!(
|
||||
word1(b'{', EEffects::ListStart),
|
||||
specialize(EEffects::TypedIdent, loc!(typed_ident())),
|
||||
word1(b',', EEffects::ListEnd),
|
||||
word1(b'}', EEffects::ListEnd),
|
||||
min_indent,
|
||||
EEffects::Open,
|
||||
EEffects::Space,
|
||||
EEffects::IndentListEnd
|
||||
EEffects::IndentListEnd,
|
||||
TypedIdent::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
|
@ -702,7 +718,7 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
|
|||
spaces_after_type_name,
|
||||
effect_shortname: type_shortname,
|
||||
effect_type_name: type_name,
|
||||
entries: entries.into_bump_slice(),
|
||||
entries,
|
||||
},
|
||||
state,
|
||||
))
|
||||
|
@ -764,7 +780,7 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> {
|
|||
|
||||
type Temp<'a> = (
|
||||
(Option<&'a str>, ModuleName<'a>),
|
||||
Option<Vec<'a, Located<ExposesEntry<'a, &'a str>>>>,
|
||||
Option<Collection<'a, Located<ExposesEntry<'a, &'a str>>>>,
|
||||
);
|
||||
|
||||
map_with_arena!(
|
||||
|
@ -781,19 +797,21 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> {
|
|||
// e.g. `.{ Task, after}`
|
||||
maybe!(skip_first!(
|
||||
word1(b'.', EImports::ExposingDot),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', EImports::SetStart),
|
||||
exposes_entry(EImports::Identifier),
|
||||
word1(b',', EImports::SetEnd),
|
||||
word1(b'}', EImports::SetEnd),
|
||||
min_indent,
|
||||
EImports::Open,
|
||||
EImports::Space,
|
||||
EImports::IndentSetEnd
|
||||
EImports::IndentSetEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
))
|
||||
),
|
||||
|arena, ((opt_shortname, module_name), opt_values): Temp<'a>| {
|
||||
let exposed_values = opt_values.unwrap_or_else(|| Vec::new_in(arena));
|
||||
|_arena, ((opt_shortname, module_name), opt_values): Temp<'a>| {
|
||||
let exposed_values = opt_values.unwrap_or_else(Collection::empty);
|
||||
|
||||
match opt_shortname {
|
||||
Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ast::Base;
|
||||
use crate::parser::{Number, ParseResult, Parser, Progress, State};
|
||||
use crate::parser::{ENumber, ParseResult, Parser, Progress, State};
|
||||
|
||||
pub enum NumLiteral<'a> {
|
||||
Float(&'a str),
|
||||
|
@ -11,7 +11,7 @@ pub enum NumLiteral<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> {
|
||||
pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> {
|
||||
move |_arena, state: State<'a>| {
|
||||
match state.bytes.get(0) {
|
||||
Some(first_byte) if (*first_byte as char).is_ascii_digit() => {
|
||||
|
@ -19,13 +19,13 @@ pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number>
|
|||
}
|
||||
_ => {
|
||||
// this is not a number at all
|
||||
Err((Progress::NoProgress, Number::End, state))
|
||||
Err((Progress::NoProgress, ENumber::End, state))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> {
|
||||
pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> {
|
||||
move |_arena, state: State<'a>| {
|
||||
match state.bytes.get(0) {
|
||||
Some(first_byte) if *first_byte == b'-' => {
|
||||
|
@ -37,7 +37,7 @@ pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> {
|
|||
}
|
||||
_ => {
|
||||
// this is not a number at all
|
||||
Err((Progress::NoProgress, Number::End, state))
|
||||
Err((Progress::NoProgress, ENumber::End, state))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ fn parse_number_base<'a>(
|
|||
is_negated: bool,
|
||||
bytes: &'a [u8],
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, NumLiteral<'a>, Number> {
|
||||
) -> ParseResult<'a, NumLiteral<'a>, ENumber> {
|
||||
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),
|
||||
|
@ -61,13 +61,13 @@ fn chomp_number_base<'a>(
|
|||
is_negative: bool,
|
||||
bytes: &'a [u8],
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, NumLiteral<'a>, Number> {
|
||||
) -> ParseResult<'a, NumLiteral<'a>, ENumber> {
|
||||
let (_is_float, chomped) = chomp_number(bytes);
|
||||
|
||||
let string = unsafe { std::str::from_utf8_unchecked(&bytes[..chomped]) };
|
||||
|
||||
let new = state.advance_without_indenting_ee(chomped + 2 + is_negative as usize, |_, _| {
|
||||
Number::LineTooLong
|
||||
ENumber::LineTooLong
|
||||
})?;
|
||||
|
||||
Ok((
|
||||
|
@ -85,24 +85,25 @@ fn chomp_number_dec<'a>(
|
|||
is_negative: bool,
|
||||
bytes: &'a [u8],
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, NumLiteral<'a>, Number> {
|
||||
) -> ParseResult<'a, NumLiteral<'a>, ENumber> {
|
||||
let (is_float, chomped) = chomp_number(bytes);
|
||||
|
||||
if is_negative && chomped == 0 {
|
||||
// we're probably actually looking at unary negation here
|
||||
return Err((Progress::NoProgress, Number::End, state));
|
||||
return Err((Progress::NoProgress, ENumber::End, state));
|
||||
}
|
||||
|
||||
if !bytes.get(0).copied().unwrap_or_default().is_ascii_digit() {
|
||||
// we're probably actually looking at unary negation here
|
||||
return Err((Progress::NoProgress, Number::End, state));
|
||||
return Err((Progress::NoProgress, ENumber::End, state));
|
||||
}
|
||||
|
||||
let string =
|
||||
unsafe { std::str::from_utf8_unchecked(&state.bytes[0..chomped + is_negative as usize]) };
|
||||
|
||||
let new = state
|
||||
.advance_without_indenting_ee(chomped + is_negative as usize, |_, _| Number::LineTooLong)?;
|
||||
let new = state.advance_without_indenting_ee(chomped + is_negative as usize, |_, _| {
|
||||
ENumber::LineTooLong
|
||||
})?;
|
||||
|
||||
Ok((
|
||||
Progress::MadeProgress,
|
||||
|
|
|
@ -186,7 +186,7 @@ pub enum SyntaxError<'a> {
|
|||
ArgumentsBeforeEquals(Region),
|
||||
NotYetImplemented(String),
|
||||
Todo,
|
||||
Type(Type<'a>),
|
||||
Type(EType<'a>),
|
||||
Pattern(EPattern<'a>),
|
||||
Expr(EExpr<'a>),
|
||||
Header(EHeader<'a>),
|
||||
|
@ -214,6 +214,7 @@ pub enum EHeader<'a> {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EProvides<'a> {
|
||||
Provides(Row, Col),
|
||||
Open(Row, Col),
|
||||
To(Row, Col),
|
||||
IndentProvides(Row, Col),
|
||||
IndentTo(Row, Col),
|
||||
|
@ -230,6 +231,7 @@ pub enum EProvides<'a> {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EExposes {
|
||||
Exposes(Row, Col),
|
||||
Open(Row, Col),
|
||||
IndentExposes(Row, Col),
|
||||
IndentListStart(Row, Col),
|
||||
IndentListEnd(Row, Col),
|
||||
|
@ -242,6 +244,7 @@ pub enum EExposes {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ERequires<'a> {
|
||||
Requires(Row, Col),
|
||||
Open(Row, Col),
|
||||
IndentRequires(Row, Col),
|
||||
IndentListStart(Row, Col),
|
||||
IndentListEnd(Row, Col),
|
||||
|
@ -258,13 +261,14 @@ pub enum ETypedIdent<'a> {
|
|||
HasType(Row, Col),
|
||||
IndentHasType(Row, Col),
|
||||
Name(Row, Col),
|
||||
Type(Type<'a>, Row, Col),
|
||||
Type(EType<'a>, Row, Col),
|
||||
IndentType(Row, Col),
|
||||
Identifier(Row, Col),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EPackages<'a> {
|
||||
Open(Row, Col),
|
||||
Space(BadInputError, Row, Col),
|
||||
Packages(Row, Col),
|
||||
IndentPackages(Row, Col),
|
||||
|
@ -301,6 +305,7 @@ pub enum EPackageEntry<'a> {
|
|||
pub enum EEffects<'a> {
|
||||
Space(BadInputError, Row, Col),
|
||||
Effects(Row, Col),
|
||||
Open(Row, Col),
|
||||
IndentEffects(Row, Col),
|
||||
ListStart(Row, Col),
|
||||
ListEnd(Row, Col),
|
||||
|
@ -314,6 +319,7 @@ pub enum EEffects<'a> {
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EImports {
|
||||
Open(Row, Col),
|
||||
Imports(Row, Col),
|
||||
IndentImports(Row, Col),
|
||||
IndentListStart(Row, Col),
|
||||
|
@ -393,7 +399,7 @@ pub enum EExpr<'a> {
|
|||
|
||||
DefMissingFinalExpr(Row, Col),
|
||||
DefMissingFinalExpr2(&'a EExpr<'a>, Row, Col),
|
||||
Type(Type<'a>, Row, Col),
|
||||
Type(EType<'a>, Row, Col),
|
||||
Pattern(&'a EPattern<'a>, Row, Col),
|
||||
IndentDefBody(Row, Col),
|
||||
IndentEquals(Row, Col),
|
||||
|
@ -408,10 +414,10 @@ pub enum EExpr<'a> {
|
|||
BackpassComma(Row, Col),
|
||||
BackpassArrow(Row, Col),
|
||||
|
||||
When(When<'a>, Row, Col),
|
||||
If(If<'a>, Row, Col),
|
||||
When(EWhen<'a>, Row, Col),
|
||||
If(EIf<'a>, Row, Col),
|
||||
|
||||
Expect(Expect<'a>, Row, Col),
|
||||
Expect(EExpect<'a>, Row, Col),
|
||||
|
||||
Lambda(ELambda<'a>, Row, Col),
|
||||
Underscore(Row, Col),
|
||||
|
@ -420,15 +426,15 @@ pub enum EExpr<'a> {
|
|||
Record(ERecord<'a>, Row, Col),
|
||||
Str(EString<'a>, Row, Col),
|
||||
SingleQuote(EString<'a>, Row, Col),
|
||||
Number(Number, Row, Col),
|
||||
List(List<'a>, Row, Col),
|
||||
Number(ENumber, Row, Col),
|
||||
List(EList<'a>, Row, Col),
|
||||
|
||||
IndentStart(Row, Col),
|
||||
IndentEnd(Row, Col),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Number {
|
||||
pub enum ENumber {
|
||||
End,
|
||||
LineTooLong,
|
||||
}
|
||||
|
@ -502,7 +508,7 @@ pub enum ELambda<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum List<'a> {
|
||||
pub enum EList<'a> {
|
||||
Open(Row, Col),
|
||||
End(Row, Col),
|
||||
Space(BadInputError, Row, Col),
|
||||
|
@ -514,7 +520,7 @@ pub enum List<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum When<'a> {
|
||||
pub enum EWhen<'a> {
|
||||
Space(BadInputError, Row, Col),
|
||||
When(Row, Col),
|
||||
Is(Row, Col),
|
||||
|
@ -538,7 +544,7 @@ pub enum When<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum If<'a> {
|
||||
pub enum EIf<'a> {
|
||||
Space(BadInputError, Row, Col),
|
||||
If(Row, Col),
|
||||
Then(Row, Col),
|
||||
|
@ -557,7 +563,7 @@ pub enum If<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Expect<'a> {
|
||||
pub enum EExpect<'a> {
|
||||
Space(BadInputError, Row, Col),
|
||||
Expect(Row, Col),
|
||||
Condition(&'a EExpr<'a>, Row, Col),
|
||||
|
@ -575,7 +581,7 @@ pub enum EPattern<'a> {
|
|||
Space(BadInputError, Row, Col),
|
||||
|
||||
PInParens(PInParens<'a>, Row, Col),
|
||||
NumLiteral(Number, Row, Col),
|
||||
NumLiteral(ENumber, Row, Col),
|
||||
|
||||
IndentStart(Row, Col),
|
||||
IndentEnd(Row, Col),
|
||||
|
@ -614,13 +620,14 @@ pub enum PInParens<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Type<'a> {
|
||||
TRecord(TRecord<'a>, Row, Col),
|
||||
TTagUnion(TTagUnion<'a>, Row, Col),
|
||||
TInParens(TInParens<'a>, Row, Col),
|
||||
TApply(TApply, Row, Col),
|
||||
pub enum EType<'a> {
|
||||
TRecord(ETypeRecord<'a>, Row, Col),
|
||||
TTagUnion(ETypeTagUnion<'a>, Row, Col),
|
||||
TInParens(ETypeInParens<'a>, Row, Col),
|
||||
TApply(ETypeApply, Row, Col),
|
||||
TBadTypeVariable(Row, Col),
|
||||
TWildcard(Row, Col),
|
||||
TInferred(Row, Col),
|
||||
///
|
||||
TStart(Row, Col),
|
||||
TEnd(Row, Col),
|
||||
|
@ -633,14 +640,14 @@ pub enum Type<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TRecord<'a> {
|
||||
pub enum ETypeRecord<'a> {
|
||||
End(Row, Col),
|
||||
Open(Row, Col),
|
||||
|
||||
Field(Row, Col),
|
||||
Colon(Row, Col),
|
||||
Optional(Row, Col),
|
||||
Type(&'a Type<'a>, Row, Col),
|
||||
Type(&'a EType<'a>, Row, Col),
|
||||
|
||||
Space(BadInputError, Row, Col),
|
||||
|
||||
|
@ -651,11 +658,11 @@ pub enum TRecord<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TTagUnion<'a> {
|
||||
pub enum ETypeTagUnion<'a> {
|
||||
End(Row, Col),
|
||||
Open(Row, Col),
|
||||
|
||||
Type(&'a Type<'a>, Row, Col),
|
||||
Type(&'a EType<'a>, Row, Col),
|
||||
|
||||
Space(BadInputError, Row, Col),
|
||||
|
||||
|
@ -664,11 +671,11 @@ pub enum TTagUnion<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TInParens<'a> {
|
||||
pub enum ETypeInParens<'a> {
|
||||
End(Row, Col),
|
||||
Open(Row, Col),
|
||||
///
|
||||
Type(&'a Type<'a>, Row, Col),
|
||||
Type(&'a EType<'a>, Row, Col),
|
||||
|
||||
///
|
||||
Space(BadInputError, Row, Col),
|
||||
|
@ -678,7 +685,7 @@ pub enum TInParens<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TApply {
|
||||
pub enum ETypeApply {
|
||||
///
|
||||
StartNotUppercase(Row, Col),
|
||||
End(Row, Col),
|
||||
|
@ -1183,132 +1190,53 @@ macro_rules! collection {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! collection_e {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $space_problem:expr, $indent_problem:expr) => {
|
||||
skip_first!(
|
||||
$opening_brace,
|
||||
skip_first!(
|
||||
// We specifically allow space characters inside here, so that
|
||||
// `[ ]` can be successfully parsed as an empty list, and then
|
||||
// changed by the formatter back into `[]`.
|
||||
//
|
||||
// We don't allow newlines or comments in the middle of empty
|
||||
// roc_collections because those are normally stored in an Expr,
|
||||
// and there's no Expr in which to store them in an empty collection!
|
||||
//
|
||||
// We could change the AST to add extra storage specifically to
|
||||
// support empty literals containing newlines or comments, but this
|
||||
// does not seem worth even the tiniest regression in compiler performance.
|
||||
zero_or_more!($crate::parser::word1(b' ', |row, col| $space_problem(
|
||||
crate::parser::BadInputError::LineTooLong,
|
||||
row,
|
||||
col
|
||||
))),
|
||||
skip_second!(
|
||||
$crate::parser::sep_by0(
|
||||
$delimiter,
|
||||
$crate::blankspace::space0_around_ee(
|
||||
$elem,
|
||||
$min_indent,
|
||||
$space_problem,
|
||||
$indent_problem,
|
||||
$indent_problem
|
||||
)
|
||||
),
|
||||
$closing_brace
|
||||
)
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/// Parse zero or more elements between two braces (e.g. square braces).
|
||||
/// Elements can be optionally surrounded by spaces, and are separated by a
|
||||
/// delimiter (e.g comma-separated) with optionally a trailing delimiter.
|
||||
/// Braces and delimiters get discarded.
|
||||
#[macro_export]
|
||||
macro_rules! collection_trailing_sep {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr) => {
|
||||
skip_first!(
|
||||
$opening_brace,
|
||||
skip_first!(
|
||||
// We specifically allow space characters inside here, so that
|
||||
// `[ ]` can be successfully parsed as an empty list, and then
|
||||
// changed by the formatter back into `[]`.
|
||||
//
|
||||
// We don't allow newlines or comments in the middle of empty
|
||||
// roc_collections because those are normally stored in an Expr,
|
||||
// and there's no Expr in which to store them in an empty collection!
|
||||
//
|
||||
// We could change the AST to add extra storage specifically to
|
||||
// support empty literals containing newlines or comments, but this
|
||||
// does not seem worth even the tiniest regression in compiler performance.
|
||||
zero_or_more!($crate::parser::ascii_char(b' ')),
|
||||
skip_second!(
|
||||
and!(
|
||||
$crate::parser::trailing_sep_by0(
|
||||
$delimiter,
|
||||
$crate::blankspace::space0_around($elem, $min_indent)
|
||||
),
|
||||
$crate::blankspace::space0($min_indent)
|
||||
),
|
||||
$closing_brace
|
||||
)
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! collection_trailing_sep_e {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $open_problem:expr, $space_problem:expr, $indent_problem:expr) => {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $open_problem:expr, $space_problem:expr, $indent_problem:expr, $space_before:expr) => {
|
||||
skip_first!(
|
||||
$opening_brace,
|
||||
skip_first!(
|
||||
// We specifically allow space characters inside here, so that
|
||||
// `[ ]` can be successfully parsed as an empty list, and then
|
||||
// changed by the formatter back into `[]`.
|
||||
//
|
||||
// We don't allow newlines or comments in the middle of empty
|
||||
// roc_collections because those are normally stored in an Expr,
|
||||
// and there's no Expr in which to store them in an empty collection!
|
||||
//
|
||||
// We could change the AST to add extra storage specifically to
|
||||
// support empty literals containing newlines or comments, but this
|
||||
// does not seem worth even the tiniest regression in compiler performance.
|
||||
zero_or_more!($crate::parser::word1(b' ', |row, col| $space_problem(
|
||||
crate::parser::BadInputError::LineTooLong,
|
||||
row,
|
||||
col
|
||||
))),
|
||||
|arena, state| {
|
||||
let (_, elements, state) =
|
||||
and!(
|
||||
$crate::parser::trailing_sep_by0(
|
||||
$delimiter,
|
||||
$crate::blankspace::space0_before_optional_after(
|
||||
$elem,
|
||||
$min_indent,
|
||||
$space_problem,
|
||||
$indent_problem,
|
||||
$indent_problem
|
||||
)
|
||||
),
|
||||
$crate::blankspace::space0_e($min_indent, $space_problem, $indent_problem)
|
||||
).parse(arena, state)?;
|
||||
|arena, state| {
|
||||
let (_, spaces, state) = space0_e($min_indent, $space_problem, $indent_problem)
|
||||
.parse(arena, state)?;
|
||||
|
||||
let (_,_, state) =
|
||||
if elements.0.is_empty() {
|
||||
one_of_with_error![$open_problem; $closing_brace].parse(arena, state)?
|
||||
} else {
|
||||
$closing_brace.parse(arena, state)?
|
||||
};
|
||||
let (_, (mut parsed_elems, mut final_comments), state) =
|
||||
and!(
|
||||
$crate::parser::trailing_sep_by0(
|
||||
$delimiter,
|
||||
$crate::blankspace::space0_before_optional_after(
|
||||
$elem,
|
||||
$min_indent,
|
||||
$space_problem,
|
||||
$indent_problem,
|
||||
$indent_problem
|
||||
)
|
||||
),
|
||||
$crate::blankspace::space0_e($min_indent, $space_problem, $indent_problem)
|
||||
).parse(arena, state)?;
|
||||
|
||||
let (_,_, state) =
|
||||
if parsed_elems.is_empty() {
|
||||
one_of_with_error![$open_problem; $closing_brace].parse(arena, state)?
|
||||
} else {
|
||||
$closing_brace.parse(arena, state)?
|
||||
};
|
||||
|
||||
Ok((MadeProgress, elements, state))
|
||||
if !spaces.is_empty() {
|
||||
if let Some(first) = parsed_elems.first_mut() {
|
||||
first.value = $space_before(arena.alloc(first.value), spaces)
|
||||
} else {
|
||||
assert!(final_comments.is_empty());
|
||||
final_comments = spaces;
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
let collection = $crate::ast::Collection::with_items_and_comments(
|
||||
arena,
|
||||
parsed_elems.into_bump_slice(),
|
||||
final_comments);
|
||||
|
||||
Ok((MadeProgress, collection, state))
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -328,7 +328,7 @@ fn lowercase_ident_pattern<'a>(
|
|||
#[inline(always)]
|
||||
fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
|
||||
move |arena, state| {
|
||||
let (_, (fields, final_comments), state) = collection_trailing_sep_e!(
|
||||
let (_, fields, state) = collection_trailing_sep_e!(
|
||||
// word1_check_indent!(b'{', PRecord::Open, min_indent, PRecord::IndentOpen),
|
||||
word1(b'{', PRecord::Open),
|
||||
record_pattern_field(min_indent),
|
||||
|
@ -338,14 +338,12 @@ fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRec
|
|||
min_indent,
|
||||
PRecord::Open,
|
||||
PRecord::Space,
|
||||
PRecord::IndentEnd
|
||||
PRecord::IndentEnd,
|
||||
Pattern::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
// TODO
|
||||
let _unused = final_comments;
|
||||
|
||||
let result = Pattern::RecordDestructure(fields.into_bump_slice());
|
||||
let result = Pattern::RecordDestructure(fields);
|
||||
|
||||
Ok((MadeProgress, result, state))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::ast;
|
||||
use crate::module::module_defs;
|
||||
// use crate::module::module_defs;
|
||||
use crate::parser::Parser;
|
||||
use crate::parser::{State, SyntaxError};
|
||||
use bumpalo::collections::Vec as BumpVec;
|
||||
use bumpalo::Bump;
|
||||
use roc_region::all::Located;
|
||||
|
||||
|
@ -23,3 +26,15 @@ pub fn parse_loc_with<'a>(
|
|||
Err(fail) => Err(SyntaxError::Expr(fail)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_defs_with<'a>(
|
||||
arena: &'a Bump,
|
||||
input: &'a str,
|
||||
) -> Result<BumpVec<'a, Located<ast::Def<'a>>>, SyntaxError<'a>> {
|
||||
let state = State::new(input.trim().as_bytes());
|
||||
|
||||
match module_defs().parse(arena, state) {
|
||||
Ok(tuple) => Ok(tuple.1),
|
||||
Err(tuple) => Err(tuple.1),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,61 +2,63 @@ use crate::ast::{AssignedField, Tag, TypeAnnotation};
|
|||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, ParseResult,
|
||||
Parser,
|
||||
allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, EType,
|
||||
ETypeApply, ETypeInParens, ETypeRecord, ETypeTagUnion, ParseResult, Parser,
|
||||
Progress::{self, *},
|
||||
State, TApply, TInParens, TRecord, TTagUnion, Type,
|
||||
State,
|
||||
};
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_region::all::{Located, Region};
|
||||
|
||||
pub fn located_help<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> {
|
||||
pub fn located_help<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
|
||||
expression(min_indent)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TTagUnion<'a>> {
|
||||
fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
|
||||
move |arena, state| {
|
||||
let (_, (tags, final_comments), state) = collection_trailing_sep_e!(
|
||||
word1(b'[', TTagUnion::Open),
|
||||
let (_, tags, state) = collection_trailing_sep_e!(
|
||||
word1(b'[', ETypeTagUnion::Open),
|
||||
loc!(tag_type(min_indent)),
|
||||
word1(b',', TTagUnion::End),
|
||||
word1(b']', TTagUnion::End),
|
||||
word1(b',', ETypeTagUnion::End),
|
||||
word1(b']', ETypeTagUnion::End),
|
||||
min_indent,
|
||||
TTagUnion::Open,
|
||||
TTagUnion::Space,
|
||||
TTagUnion::IndentEnd
|
||||
ETypeTagUnion::Open,
|
||||
ETypeTagUnion::Space,
|
||||
ETypeTagUnion::IndentEnd,
|
||||
Tag::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
// This could be an open tag union, e.g. `[ Foo, Bar ]a`
|
||||
let (_, ext, state) =
|
||||
optional(allocated(specialize_ref(TTagUnion::Type, term(min_indent))))
|
||||
.parse(arena, state)?;
|
||||
let (_, ext, state) = optional(allocated(specialize_ref(
|
||||
ETypeTagUnion::Type,
|
||||
term(min_indent),
|
||||
)))
|
||||
.parse(arena, state)?;
|
||||
|
||||
let result = TypeAnnotation::TagUnion {
|
||||
tags: tags.into_bump_slice(),
|
||||
ext,
|
||||
final_comments,
|
||||
};
|
||||
let result = TypeAnnotation::TagUnion { tags, ext };
|
||||
|
||||
Ok((MadeProgress, result, state))
|
||||
}
|
||||
}
|
||||
|
||||
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, Type<'a>> {
|
||||
|_arena, state: State<'a>| Err((NoProgress, Type::TStart(state.line, state.column), state))
|
||||
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, EType<'a>> {
|
||||
|_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.line, state.column), state))
|
||||
}
|
||||
|
||||
fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> {
|
||||
fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
|
||||
map_with_arena!(
|
||||
and!(
|
||||
one_of!(
|
||||
loc_wildcard(),
|
||||
specialize(Type::TInParens, loc_type_in_parens(min_indent)),
|
||||
loc!(specialize(Type::TRecord, record_type(min_indent))),
|
||||
loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))),
|
||||
loc_inferred(),
|
||||
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
||||
loc!(specialize(EType::TRecord, record_type(min_indent))),
|
||||
loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))),
|
||||
loc!(applied_type(min_indent)),
|
||||
loc!(parse_type_variable),
|
||||
fail_type_start(),
|
||||
|
@ -66,14 +68,14 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Typ
|
|||
map!(
|
||||
and!(
|
||||
skip_second!(
|
||||
backtrackable(space0_e(min_indent, Type::TSpace, Type::TIndentEnd)),
|
||||
crate::parser::keyword_e(keyword::AS, Type::TEnd)
|
||||
backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentEnd)),
|
||||
crate::parser::keyword_e(keyword::AS, EType::TEnd)
|
||||
),
|
||||
space0_before_e(
|
||||
term(min_indent),
|
||||
min_indent,
|
||||
Type::TSpace,
|
||||
Type::TAsIndentStart
|
||||
EType::TSpace,
|
||||
EType::TAsIndentStart
|
||||
)
|
||||
),
|
||||
Some
|
||||
|
@ -102,24 +104,36 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Typ
|
|||
}
|
||||
|
||||
/// The `*` type variable, e.g. in (List *) Wildcard,
|
||||
fn loc_wildcard<'a>() -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> {
|
||||
map!(loc!(word1(b'*', Type::TWildcard)), |loc_val: Located<()>| {
|
||||
fn loc_wildcard<'a>() -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
|
||||
map!(loc!(word1(b'*', EType::TWildcard)), |loc_val: Located<
|
||||
(),
|
||||
>| {
|
||||
loc_val.map(|_| TypeAnnotation::Wildcard)
|
||||
})
|
||||
}
|
||||
|
||||
fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> {
|
||||
/// The `_` indicating an inferred type, e.g. in (List _)
|
||||
fn loc_inferred<'a>() -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
|
||||
map!(loc!(word1(b'_', EType::TInferred)), |loc_val: Located<
|
||||
(),
|
||||
>| {
|
||||
loc_val.map(|_| TypeAnnotation::Inferred)
|
||||
})
|
||||
}
|
||||
|
||||
fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
|
||||
use crate::ast::Spaceable;
|
||||
|
||||
map_with_arena!(
|
||||
and!(
|
||||
backtrackable(space0_e(min_indent, Type::TSpace, Type::TIndentStart)),
|
||||
backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentStart)),
|
||||
one_of!(
|
||||
loc_wildcard(),
|
||||
specialize(Type::TInParens, loc_type_in_parens(min_indent)),
|
||||
loc!(specialize(Type::TRecord, record_type(min_indent))),
|
||||
loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))),
|
||||
loc!(specialize(Type::TApply, parse_concrete_type)),
|
||||
loc_inferred(),
|
||||
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
||||
loc!(specialize(EType::TRecord, record_type(min_indent))),
|
||||
loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))),
|
||||
loc!(specialize(EType::TApply, parse_concrete_type)),
|
||||
loc!(parse_type_variable)
|
||||
)
|
||||
),
|
||||
|
@ -136,28 +150,28 @@ fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotatio
|
|||
|
||||
fn loc_type_in_parens<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, TInParens<'a>> {
|
||||
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, ETypeInParens<'a>> {
|
||||
between!(
|
||||
word1(b'(', TInParens::Open),
|
||||
word1(b'(', ETypeInParens::Open),
|
||||
space0_around_ee(
|
||||
move |arena, state| specialize_ref(TInParens::Type, expression(min_indent))
|
||||
move |arena, state| specialize_ref(ETypeInParens::Type, expression(min_indent))
|
||||
.parse(arena, state),
|
||||
min_indent,
|
||||
TInParens::Space,
|
||||
TInParens::IndentOpen,
|
||||
TInParens::IndentEnd,
|
||||
ETypeInParens::Space,
|
||||
ETypeInParens::IndentOpen,
|
||||
ETypeInParens::IndentEnd,
|
||||
),
|
||||
word1(b')', TInParens::IndentEnd)
|
||||
word1(b')', ETypeInParens::IndentEnd)
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tag_type<'a>(min_indent: u16) -> impl Parser<'a, Tag<'a>, TTagUnion<'a>> {
|
||||
fn tag_type<'a>(min_indent: u16) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let (_, name, state) = loc!(parse_tag_name(TTagUnion::End)).parse(arena, state)?;
|
||||
let (_, name, state) = loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state)?;
|
||||
|
||||
let (_, args, state) =
|
||||
specialize_ref(TTagUnion::Type, loc_applied_args_e(min_indent)).parse(arena, state)?;
|
||||
let (_, args, state) = specialize_ref(ETypeTagUnion::Type, loc_applied_args_e(min_indent))
|
||||
.parse(arena, state)?;
|
||||
|
||||
let result = if name.value.starts_with('@') {
|
||||
Tag::Private {
|
||||
|
@ -189,7 +203,7 @@ where
|
|||
|
||||
fn record_type_field<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, TRecord<'a>> {
|
||||
) -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, ETypeRecord<'a>> {
|
||||
use crate::ident::lowercase_ident;
|
||||
use crate::parser::Either::*;
|
||||
use AssignedField::*;
|
||||
|
@ -200,30 +214,34 @@ fn record_type_field<'a>(
|
|||
let row = state.line;
|
||||
let col = state.column;
|
||||
let (progress, loc_label, state) = loc!(specialize(
|
||||
move |_, _, _| TRecord::Field(row, col),
|
||||
move |_, _, _| ETypeRecord::Field(row, col),
|
||||
lowercase_ident()
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
debug_assert_eq!(progress, MadeProgress);
|
||||
|
||||
let (_, spaces, state) =
|
||||
space0_e(min_indent, TRecord::Space, TRecord::IndentEnd).parse(arena, state)?;
|
||||
space0_e(min_indent, ETypeRecord::Space, ETypeRecord::IndentEnd).parse(arena, state)?;
|
||||
|
||||
// Having a value is optional; both `{ email }` and `{ email: blah }` work.
|
||||
// (This is true in both literals and types.)
|
||||
let (_, opt_loc_val, state) = optional(either!(
|
||||
word1(b':', TRecord::Colon),
|
||||
word1(b'?', TRecord::Optional)
|
||||
word1(b':', ETypeRecord::Colon),
|
||||
word1(b'?', ETypeRecord::Optional)
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
|
||||
let val_parser = specialize_ref(TRecord::Type, term(min_indent));
|
||||
let val_parser = specialize_ref(ETypeRecord::Type, term(min_indent));
|
||||
|
||||
match opt_loc_val {
|
||||
Some(First(_)) => {
|
||||
let (_, loc_val, state) =
|
||||
space0_before_e(val_parser, min_indent, TRecord::Space, TRecord::IndentColon)
|
||||
.parse(arena, state)?;
|
||||
let (_, loc_val, state) = space0_before_e(
|
||||
val_parser,
|
||||
min_indent,
|
||||
ETypeRecord::Space,
|
||||
ETypeRecord::IndentColon,
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
Ok((
|
||||
MadeProgress,
|
||||
|
@ -235,8 +253,8 @@ fn record_type_field<'a>(
|
|||
let (_, loc_val, state) = space0_before_e(
|
||||
val_parser,
|
||||
min_indent,
|
||||
TRecord::Space,
|
||||
TRecord::IndentOptional,
|
||||
ETypeRecord::Space,
|
||||
ETypeRecord::IndentOptional,
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
|
@ -262,41 +280,38 @@ fn record_type_field<'a>(
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TRecord<'a>> {
|
||||
fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
|
||||
use crate::type_annotation::TypeAnnotation::*;
|
||||
|
||||
move |arena, state| {
|
||||
let (_, (fields, final_comments), state) = collection_trailing_sep_e!(
|
||||
let (_, fields, state) = collection_trailing_sep_e!(
|
||||
// word1_check_indent!(b'{', TRecord::Open, min_indent, TRecord::IndentOpen),
|
||||
word1(b'{', TRecord::Open),
|
||||
word1(b'{', ETypeRecord::Open),
|
||||
loc!(record_type_field(min_indent)),
|
||||
word1(b',', TRecord::End),
|
||||
word1(b',', ETypeRecord::End),
|
||||
// word1_check_indent!(b'}', TRecord::End, min_indent, TRecord::IndentEnd),
|
||||
word1(b'}', TRecord::End),
|
||||
word1(b'}', ETypeRecord::End),
|
||||
min_indent,
|
||||
TRecord::Open,
|
||||
TRecord::Space,
|
||||
TRecord::IndentEnd
|
||||
ETypeRecord::Open,
|
||||
ETypeRecord::Space,
|
||||
ETypeRecord::IndentEnd,
|
||||
AssignedField::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
let field_term = specialize_ref(TRecord::Type, term(min_indent));
|
||||
let field_term = specialize_ref(ETypeRecord::Type, term(min_indent));
|
||||
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?;
|
||||
|
||||
let result = Record {
|
||||
fields: fields.into_bump_slice(),
|
||||
ext,
|
||||
final_comments,
|
||||
};
|
||||
let result = Record { fields, ext };
|
||||
|
||||
Ok((MadeProgress, result, state))
|
||||
}
|
||||
}
|
||||
|
||||
fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, Type<'a>> {
|
||||
fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||
map!(
|
||||
and!(
|
||||
specialize(Type::TApply, parse_concrete_type),
|
||||
specialize(EType::TApply, parse_concrete_type),
|
||||
// Optionally parse space-separated arguments for the constructor,
|
||||
// e.g. `Str Float` in `Map Str Float`
|
||||
loc_applied_args_e(min_indent)
|
||||
|
@ -320,33 +335,33 @@ fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, Type
|
|||
|
||||
fn loc_applied_args_e<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Vec<'a, Located<TypeAnnotation<'a>>>, Type<'a>> {
|
||||
) -> impl Parser<'a, Vec<'a, Located<TypeAnnotation<'a>>>, EType<'a>> {
|
||||
zero_or_more!(loc_applied_arg(min_indent))
|
||||
}
|
||||
|
||||
fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> {
|
||||
fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let (p1, first, state) = space0_before_e(
|
||||
term(min_indent),
|
||||
min_indent,
|
||||
Type::TSpace,
|
||||
Type::TIndentStart,
|
||||
EType::TSpace,
|
||||
EType::TIndentStart,
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
let (p2, rest, state) = zero_or_more!(skip_first!(
|
||||
word1(b',', Type::TFunctionArgument),
|
||||
word1(b',', EType::TFunctionArgument),
|
||||
one_of![
|
||||
space0_around_ee(
|
||||
term(min_indent),
|
||||
min_indent,
|
||||
Type::TSpace,
|
||||
Type::TIndentStart,
|
||||
Type::TIndentEnd
|
||||
EType::TSpace,
|
||||
EType::TIndentStart,
|
||||
EType::TIndentEnd
|
||||
),
|
||||
|_, state: State<'a>| Err((
|
||||
NoProgress,
|
||||
Type::TFunctionArgument(state.line, state.column),
|
||||
EType::TFunctionArgument(state.line, state.column),
|
||||
state
|
||||
))
|
||||
]
|
||||
|
@ -356,8 +371,8 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
|
|||
// TODO this space0 is dropped, so newlines just before the function arrow when there
|
||||
// is only one argument are not seen by the formatter. Can we do better?
|
||||
let (p3, is_function, state) = optional(skip_first!(
|
||||
space0_e(min_indent, Type::TSpace, Type::TIndentStart),
|
||||
word2(b'-', b'>', Type::TStart)
|
||||
space0_e(min_indent, EType::TSpace, EType::TIndentStart),
|
||||
word2(b'-', b'>', EType::TStart)
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
|
||||
|
@ -365,8 +380,8 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
|
|||
let (p4, return_type, state) = space0_before_e(
|
||||
term(min_indent),
|
||||
min_indent,
|
||||
Type::TSpace,
|
||||
Type::TIndentStart,
|
||||
EType::TSpace,
|
||||
EType::TIndentStart,
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
|
@ -414,7 +429,7 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
|
|||
fn parse_concrete_type<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, TypeAnnotation<'a>, TApply> {
|
||||
) -> ParseResult<'a, TypeAnnotation<'a>, ETypeApply> {
|
||||
let initial_bytes = state.bytes;
|
||||
|
||||
match crate::ident::concrete_type().parse(arena, state) {
|
||||
|
@ -424,7 +439,7 @@ fn parse_concrete_type<'a>(
|
|||
Ok((MadeProgress, answer, state))
|
||||
}
|
||||
Err((NoProgress, _, state)) => {
|
||||
Err((NoProgress, TApply::End(state.line, state.column), state))
|
||||
Err((NoProgress, ETypeApply::End(state.line, state.column), state))
|
||||
}
|
||||
Err((MadeProgress, _, mut state)) => {
|
||||
// we made some progress, but ultimately failed.
|
||||
|
@ -435,7 +450,7 @@ fn parse_concrete_type<'a>(
|
|||
unsafe { std::str::from_utf8_unchecked(&initial_bytes[..chomped + delta]) };
|
||||
|
||||
state = state.advance_without_indenting_ee(chomped, |r, c| {
|
||||
TApply::Space(crate::parser::BadInputError::LineTooLong, r, c)
|
||||
ETypeApply::Space(crate::parser::BadInputError::LineTooLong, r, c)
|
||||
})?;
|
||||
|
||||
Ok((MadeProgress, TypeAnnotation::Malformed(parsed_str), state))
|
||||
|
@ -446,7 +461,7 @@ fn parse_concrete_type<'a>(
|
|||
fn parse_type_variable<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, TypeAnnotation<'a>, Type<'a>> {
|
||||
) -> ParseResult<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||
match crate::ident::lowercase_ident().parse(arena, state) {
|
||||
Ok((_, name, state)) => {
|
||||
let answer = TypeAnnotation::BoundVariable(name);
|
||||
|
@ -455,7 +470,7 @@ fn parse_type_variable<'a>(
|
|||
}
|
||||
Err((progress, _, state)) => Err((
|
||||
progress,
|
||||
Type::TBadTypeVariable(state.line, state.column),
|
||||
EType::TBadTypeVariable(state.line, state.column),
|
||||
state,
|
||||
)),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue