mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Get basic def working
This commit is contained in:
parent
f6ecc88d9c
commit
fda3d3056a
8 changed files with 323 additions and 152 deletions
|
@ -948,6 +948,9 @@ fn add_idents_from_pattern<'a>(
|
||||||
(symbol, region.clone()),
|
(symbol, region.clone()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
&QualifiedIdentifier(name) => {
|
||||||
|
panic!("TODO implement QualifiedIdentifier pattern.");
|
||||||
|
}
|
||||||
&Apply(_) => {
|
&Apply(_) => {
|
||||||
panic!("TODO implement Apply pattern.");
|
panic!("TODO implement Apply pattern.");
|
||||||
// &AppliedVariant(_, ref opt_loc_args) => match opt_loc_args {
|
// &AppliedVariant(_, ref opt_loc_args) => match opt_loc_args {
|
||||||
|
@ -972,6 +975,7 @@ fn add_idents_from_pattern<'a>(
|
||||||
| &FloatLiteral(_)
|
| &FloatLiteral(_)
|
||||||
| &StrLiteral(_)
|
| &StrLiteral(_)
|
||||||
| &EmptyRecordLiteral
|
| &EmptyRecordLiteral
|
||||||
|
| &Malformed(_)
|
||||||
| &Underscore => (),
|
| &Underscore => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -983,6 +987,9 @@ fn remove_idents(pattern: &ast::Pattern, idents: &mut ImMap<Ident, (Symbol, Regi
|
||||||
Identifier(name) => {
|
Identifier(name) => {
|
||||||
idents.remove(&(Ident::Unqualified(name.to_string())));
|
idents.remove(&(Ident::Unqualified(name.to_string())));
|
||||||
}
|
}
|
||||||
|
QualifiedIdentifier(name) => {
|
||||||
|
panic!("TODO implement QualifiedIdentifier pattern in remove_idents.");
|
||||||
|
}
|
||||||
Apply(_) => {
|
Apply(_) => {
|
||||||
panic!("TODO implement Apply pattern in remove_idents.");
|
panic!("TODO implement Apply pattern in remove_idents.");
|
||||||
// AppliedVariant(_, Some(loc_args)) => {
|
// AppliedVariant(_, Some(loc_args)) => {
|
||||||
|
@ -1003,6 +1010,7 @@ fn remove_idents(pattern: &ast::Pattern, idents: &mut ImMap<Ident, (Symbol, Regi
|
||||||
| FloatLiteral(_)
|
| FloatLiteral(_)
|
||||||
| StrLiteral(_)
|
| StrLiteral(_)
|
||||||
| EmptyRecordLiteral
|
| EmptyRecordLiteral
|
||||||
|
| Malformed(_)
|
||||||
| Underscore => {}
|
| Underscore => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use bumpalo::collections::vec::Vec;
|
||||||
use bumpalo::collections::String;
|
use bumpalo::collections::String;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use operator::Operator;
|
use operator::Operator;
|
||||||
|
use parse::ident::{Ident, MaybeQualified};
|
||||||
use region::{Loc, Region};
|
use region::{Loc, Region};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -55,7 +56,12 @@ pub enum Expr<'a> {
|
||||||
When(&'a [(Loc<Pattern<'a>>, Loc<Expr<'a>>)]),
|
When(&'a [(Loc<Pattern<'a>>, Loc<Expr<'a>>)]),
|
||||||
Closure(&'a (Vec<'a, Loc<Pattern<'a>>>, Loc<Expr<'a>>)),
|
Closure(&'a (Vec<'a, Loc<Pattern<'a>>>, Loc<Expr<'a>>)),
|
||||||
/// Multiple defs in a row
|
/// Multiple defs in a row
|
||||||
Defs(&'a (Vec<'a, Def<'a>>, Loc<Expr<'a>>)),
|
Defs(
|
||||||
|
&'a (
|
||||||
|
Vec<'a, (&'a [CommentOrNewline<'a>], Def<'a>)>,
|
||||||
|
Loc<Expr<'a>>,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
// Application
|
// Application
|
||||||
/// To apply by name, do Apply(Var(...), ...)
|
/// To apply by name, do Apply(Var(...), ...)
|
||||||
|
@ -115,6 +121,53 @@ pub enum Pattern<'a> {
|
||||||
// Space
|
// Space
|
||||||
SpaceBefore(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceBefore(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
SpaceAfter(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceAfter(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
|
||||||
|
// Malformed
|
||||||
|
Malformed(&'a str),
|
||||||
|
QualifiedIdentifier(MaybeQualified<'a, &'a str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Pattern<'a> {
|
||||||
|
pub fn from_ident(arena: &'a Bump, ident: Ident<'a>) -> Pattern<'a> {
|
||||||
|
match ident {
|
||||||
|
Ident::Var(maybe_qualified) => {
|
||||||
|
if maybe_qualified.module_parts.is_empty() {
|
||||||
|
Pattern::Identifier(maybe_qualified.value)
|
||||||
|
} else {
|
||||||
|
Pattern::Variant(maybe_qualified.module_parts, maybe_qualified.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ident::Variant(maybe_qualified) => {
|
||||||
|
Pattern::Variant(maybe_qualified.module_parts, maybe_qualified.value)
|
||||||
|
}
|
||||||
|
Ident::Field(maybe_qualified) => {
|
||||||
|
let mut buf = String::with_capacity_in(
|
||||||
|
maybe_qualified.module_parts.len() + maybe_qualified.value.len(),
|
||||||
|
arena,
|
||||||
|
);
|
||||||
|
|
||||||
|
for part in maybe_qualified.module_parts.iter() {
|
||||||
|
buf.push_str(part);
|
||||||
|
buf.push('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut iter = maybe_qualified.value.iter().peekable();
|
||||||
|
|
||||||
|
while let Some(part) = iter.next() {
|
||||||
|
buf.push_str(part);
|
||||||
|
|
||||||
|
// If there are more fields to come, add a "."
|
||||||
|
if iter.peek().is_some() {
|
||||||
|
buf.push('.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern::Malformed(buf.into_bump_str())
|
||||||
|
}
|
||||||
|
Ident::AccessorFunction(string) => Pattern::Malformed(string),
|
||||||
|
Ident::Malformed(string) => Pattern::Malformed(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Spaceable<'a> {
|
pub trait Spaceable<'a> {
|
||||||
|
@ -235,6 +288,7 @@ pub enum Attempting {
|
||||||
InterpolatedString,
|
InterpolatedString,
|
||||||
NumberLiteral,
|
NumberLiteral,
|
||||||
UnicodeEscape,
|
UnicodeEscape,
|
||||||
|
Def,
|
||||||
Expression,
|
Expression,
|
||||||
Module,
|
Module,
|
||||||
Identifier,
|
Identifier,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use parse::parser::{unexpected, unexpected_eof, ParseResult, Parser, State};
|
||||||
/// appear. This way, canonicalization can give more helpful error messages like
|
/// appear. This way, canonicalization can give more helpful error messages like
|
||||||
/// "you can't redefine this variant!" if you wrote `Foo = ...` or
|
/// "you can't redefine this variant!" if you wrote `Foo = ...` or
|
||||||
/// "you can only define unqualified constants" if you wrote `Foo.bar = ...`
|
/// "you can only define unqualified constants" if you wrote `Foo.bar = ...`
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Ident<'a> {
|
pub enum Ident<'a> {
|
||||||
/// foo or Bar.Baz.foo
|
/// foo or Bar.Baz.foo
|
||||||
Var(MaybeQualified<'a, &'a str>),
|
Var(MaybeQualified<'a, &'a str>),
|
||||||
|
@ -23,14 +23,56 @@ pub enum Ident<'a> {
|
||||||
Malformed(&'a str),
|
Malformed(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Ident<'a> {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
use self::Ident::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Var(string) => string.len(),
|
||||||
|
Variant(string) => string.len(),
|
||||||
|
Field(string) => string.len(),
|
||||||
|
AccessorFunction(string) => string.len(),
|
||||||
|
Malformed(string) => string.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An optional qualifier (the `Foo.Bar` in `Foo.Bar.baz`).
|
/// An optional qualifier (the `Foo.Bar` in `Foo.Bar.baz`).
|
||||||
/// If module_parts is empty, this is unqualified.
|
/// If module_parts is empty, this is unqualified.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct MaybeQualified<'a, Val> {
|
pub struct MaybeQualified<'a, Val> {
|
||||||
pub module_parts: &'a [&'a str],
|
pub module_parts: &'a [&'a str],
|
||||||
pub value: Val,
|
pub value: Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> MaybeQualified<'a, &'a str> {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
let mut answer = self.value.len();
|
||||||
|
|
||||||
|
for part in self.module_parts {
|
||||||
|
answer += part.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MaybeQualified<'a, &'a [&'a str]> {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
let mut answer = 0;
|
||||||
|
|
||||||
|
for module_part in self.module_parts {
|
||||||
|
answer += module_part.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
for value_part in self.module_parts {
|
||||||
|
answer += value_part.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse an identifier into a string.
|
/// Parse an identifier into a string.
|
||||||
///
|
///
|
||||||
/// This is separate from the `ident` Parser because string interpolation
|
/// This is separate from the `ident` Parser because string interpolation
|
||||||
|
|
|
@ -24,8 +24,10 @@ use bumpalo::collections::String;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use operator::Operator;
|
use operator::Operator;
|
||||||
use parse::ast::{Attempting, Def, Expr, Pattern, Spaceable};
|
use parse::ast::{Attempting, CommentOrNewline, Def, Expr, Pattern, Spaceable};
|
||||||
use parse::blankspace::{space0, space0_around, space0_before, space1_before};
|
use parse::blankspace::{
|
||||||
|
space0, space0_after, space0_around, space0_before, space1, space1_before,
|
||||||
|
};
|
||||||
use parse::ident::{ident, Ident};
|
use parse::ident::{ident, Ident};
|
||||||
use parse::number_literal::number_literal;
|
use parse::number_literal::number_literal;
|
||||||
use parse::parser::{
|
use parse::parser::{
|
||||||
|
@ -185,19 +187,38 @@ pub fn loc_parenthetical_expr<'a>(min_indent: u16) -> impl Parser<'a, Located<Ex
|
||||||
/// * A type annotation
|
/// * A type annotation
|
||||||
/// * Both
|
/// * Both
|
||||||
pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
||||||
move |arena, state| panic!("TODO parse a single def")
|
// TODO support type annotations
|
||||||
|
map_with_arena(
|
||||||
|
and(
|
||||||
|
skip_second(
|
||||||
|
space0_after(loc_closure_param(min_indent), min_indent),
|
||||||
|
char('='),
|
||||||
|
),
|
||||||
|
space0_before(
|
||||||
|
loc(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||||
|
min_indent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|arena, (loc_pattern, loc_expr)| {
|
||||||
|
// BodyOnly(Loc<Pattern<'a>>, &'a Loc<Expr<'a>>),
|
||||||
|
Def::BodyOnly(loc_pattern, arena.alloc(loc_expr))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as def() but with space_before1 before each def, because each nested def must
|
/// Same as def() but with space_before1 before each def, because each nested def must
|
||||||
/// have space separating it from the previous def.
|
/// have space separating it from the previous def.
|
||||||
pub fn nested_def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
pub fn nested_def<'a>(min_indent: u16) -> impl Parser<'a, (&'a [CommentOrNewline<'a>], Def<'a>)> {
|
||||||
then(def(min_indent), move |arena: &'a Bump, state, def_val| {
|
then(
|
||||||
panic!("TODO actually parse the def with space_before1");
|
and(space1(min_indent), def(min_indent)),
|
||||||
Ok((def_val, state))
|
move |arena: &'a Bump, state, tuple| {
|
||||||
})
|
// TODO verify spacing (I think?)
|
||||||
|
Ok((tuple, state))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_def_expr<'a, S>(
|
fn parse_def_expr<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
equals_sign_indent: u16,
|
equals_sign_indent: u16,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -221,8 +242,11 @@ fn parse_def_expr<'a, S>(
|
||||||
and(
|
and(
|
||||||
// Optionally parse additional defs.
|
// Optionally parse additional defs.
|
||||||
zero_or_more(nested_def(original_indent)),
|
zero_or_more(nested_def(original_indent)),
|
||||||
// Parse the final
|
// Parse the final expression that will be returned
|
||||||
|
space1_before(
|
||||||
loc(move |arena, state| parse_expr(original_indent + 1, arena, state)),
|
loc(move |arena, state| parse_expr(original_indent + 1, arena, state)),
|
||||||
|
original_indent + 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
move |arena, state, (loc_first_body, (mut defs, loc_ret))| {
|
move |arena, state, (loc_first_body, (mut defs, loc_ret))| {
|
||||||
|
@ -237,7 +261,7 @@ fn parse_def_expr<'a, S>(
|
||||||
// reorder the first one to the end, because canonicalize will
|
// reorder the first one to the end, because canonicalize will
|
||||||
// re-sort all of these based on dependencies anyway. Only
|
// re-sort all of these based on dependencies anyway. Only
|
||||||
// their regions will ever be visible to the user.)
|
// their regions will ever be visible to the user.)
|
||||||
defs.push(first_def);
|
defs.push((&[], first_def));
|
||||||
|
|
||||||
Ok((Expr::Defs(arena.alloc((defs, loc_ret))), state))
|
Ok((Expr::Defs(arena.alloc((defs, loc_ret))), state))
|
||||||
}
|
}
|
||||||
|
@ -426,7 +450,7 @@ pub fn loc_function_args<'a>(min_indent: u16) -> impl Parser<'a, Vec<'a, Located
|
||||||
/// 4. The beginning of a type annotation (e.g. `foo :`)
|
/// 4. The beginning of a type annotation (e.g. `foo :`)
|
||||||
/// 5. A reserved keyword (e.g. `if ` or `case `), meaning we should do something else.
|
/// 5. A reserved keyword (e.g. `if ` or `case `), meaning we should do something else.
|
||||||
pub fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
pub fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
map_with_arena(
|
then(
|
||||||
and(
|
and(
|
||||||
loc(ident()),
|
loc(ident()),
|
||||||
optional(either(
|
optional(either(
|
||||||
|
@ -438,32 +462,67 @@ pub fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
// If there aren't any args, there may be a '=' or ':' after it.
|
// If there aren't any args, there may be a '=' or ':' after it.
|
||||||
// (It's a syntax error to write e.g. `foo bar =` - so if there
|
// (It's a syntax error to write e.g. `foo bar =` - so if there
|
||||||
// were any args, there is definitely no need to parse '=' or ':'!)
|
// were any args, there is definitely no need to parse '=' or ':'!)
|
||||||
and(space0(min_indent), either(char('='), char(':'))),
|
and(space0(min_indent), either(equals_with_indent(), char(':'))),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
|arena, (loc_ident, opt_extras)| {
|
move |arena, state, (loc_ident, opt_extras)| {
|
||||||
// This appears to be a var, keyword, or function application.
|
// This appears to be a var, keyword, or function application.
|
||||||
match opt_extras {
|
match opt_extras {
|
||||||
Some(Either::First(loc_args)) => {
|
Some(Either::First(loc_args)) => {
|
||||||
|
let len = loc_ident.value.len();
|
||||||
let loc_expr = Located {
|
let loc_expr = Located {
|
||||||
region: loc_ident.region,
|
region: loc_ident.region,
|
||||||
value: ident_to_expr(loc_ident.value),
|
value: ident_to_expr(loc_ident.value),
|
||||||
};
|
};
|
||||||
|
|
||||||
Expr::Apply(arena.alloc((loc_expr, loc_args)))
|
Ok((Expr::Apply(arena.alloc((loc_expr, loc_args))), state))
|
||||||
}
|
}
|
||||||
Some(Either::Second((_space_list, Either::First(())))) => {
|
Some(Either::Second((_space_list, Either::First(indent)))) => {
|
||||||
panic!("TODO handle def, making sure not to drop comments!");
|
let value: Pattern<'a> = Pattern::from_ident(arena, loc_ident.value);
|
||||||
|
let region = loc_ident.region;
|
||||||
|
let loc_pattern = Located { region, value };
|
||||||
|
|
||||||
|
parse_def_expr(min_indent, indent, arena, state, loc_pattern)
|
||||||
}
|
}
|
||||||
Some(Either::Second((_space_list, Either::Second(())))) => {
|
Some(Either::Second((_space_list, Either::Second(())))) => {
|
||||||
panic!("TODO handle annotation, making sure not to drop comments!");
|
panic!("TODO handle annotation, making sure not to drop comments!");
|
||||||
}
|
}
|
||||||
None => ident_to_expr(loc_ident.value),
|
None => {
|
||||||
|
let ident = loc_ident.value.clone();
|
||||||
|
let len = ident.len();
|
||||||
|
|
||||||
|
Ok((ident_to_expr(ident), state))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn equals_with_indent<'a>() -> impl Parser<'a, u16> {
|
||||||
|
move |_arena, state: State<'a>| {
|
||||||
|
let mut iter = state.input.chars();
|
||||||
|
|
||||||
|
match iter.next() {
|
||||||
|
Some(ch) if ch == '=' => {
|
||||||
|
match iter.peekable().peek() {
|
||||||
|
// The '=' must not be followed by another `=` or `>`
|
||||||
|
Some(next_ch) if next_ch != &'=' && next_ch != &'>' => {
|
||||||
|
Ok((state.indent_col, state.advance_without_indenting(1)?))
|
||||||
|
}
|
||||||
|
Some(next_ch) => Err(unexpected(*next_ch, 0, state, Attempting::Def)),
|
||||||
|
None => Err(unexpected_eof(
|
||||||
|
1,
|
||||||
|
Attempting::Def,
|
||||||
|
state.advance_without_indenting(1)?,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(ch) => Err(unexpected(ch, 0, state, Attempting::Def)),
|
||||||
|
None => Err(unexpected_eof(0, Attempting::Def, state)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ident_to_expr<'a>(src: Ident<'a>) -> Expr<'a> {
|
fn ident_to_expr<'a>(src: Ident<'a>) -> Expr<'a> {
|
||||||
match src {
|
match src {
|
||||||
Ident::Var(info) => Expr::Var(info.module_parts, info.value),
|
Ident::Var(info) => Expr::Var(info.module_parts, info.value),
|
||||||
|
|
|
@ -209,31 +209,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
|
||||||
where
|
|
||||||
P: Parser<'a, Before>,
|
|
||||||
F: Fn(&'a Bump, Before) -> After,
|
|
||||||
{
|
|
||||||
map_with_arena_impl(parser, transform)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn map_with_arena_impl<'a, P, F, Before, After>(
|
|
||||||
parser: P,
|
|
||||||
transform: F,
|
|
||||||
) -> impl Parser<'a, After>
|
|
||||||
where
|
|
||||||
P: Parser<'a, Before>,
|
|
||||||
F: Fn(&'a Bump, Before) -> After,
|
|
||||||
{
|
|
||||||
move |arena, state| {
|
|
||||||
parser
|
|
||||||
.parse(arena, state)
|
|
||||||
.map(|(output, next_state)| (transform(arena, output), next_state))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn attempt<'a, P, Val>(attempting: Attempting, parser: P) -> impl Parser<'a, Val>
|
pub fn attempt<'a, P, Val>(attempting: Attempting, parser: P) -> impl Parser<'a, Val>
|
||||||
where
|
where
|
||||||
|
@ -1114,6 +1089,28 @@ where
|
||||||
BoxedParser::new(and_impl(p1, p2))
|
BoxedParser::new(and_impl(p1, p2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Before>,
|
||||||
|
F: Fn(&'a Bump, Before) -> After,
|
||||||
|
{
|
||||||
|
map_with_arena_impl(parser, transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn map_with_arena_impl<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Before>,
|
||||||
|
F: Fn(&'a Bump, Before) -> After,
|
||||||
|
{
|
||||||
|
move |arena, state| {
|
||||||
|
parser
|
||||||
|
.parse(arena, state)
|
||||||
|
.map(|(output, next_state)| (transform(arena, output), next_state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> BoxedParser<'a, After>
|
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> BoxedParser<'a, After>
|
||||||
where
|
where
|
||||||
|
|
|
@ -38,8 +38,8 @@ impl fmt::Debug for Region {
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"|L {}, C {} - L {}, C {}|",
|
"|L {}-{}, C {}-{}|",
|
||||||
self.start_line, self.start_col, self.end_line, self.end_col,
|
self.start_line, self.end_line, self.start_col, self.end_col,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,125 +312,125 @@ mod test_infer {
|
||||||
|
|
||||||
// DEF
|
// DEF
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_empty_record() {
|
// fn def_empty_record() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
foo = {}
|
// foo = {}
|
||||||
|
|
||||||
foo
|
// foo
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"{}",
|
// "{}",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_string() {
|
// fn def_string() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
str = "thing"
|
// str = "thing"
|
||||||
|
|
||||||
str
|
// str
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"Str",
|
// "Str",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_1_arg_closure() {
|
// fn def_1_arg_closure() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
fn = \_ -> {}
|
// fn = \_ -> {}
|
||||||
|
|
||||||
fn
|
// fn
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"* -> {}",
|
// "* -> {}",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_2_arg_closure() {
|
// fn def_2_arg_closure() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
func = \_ _ -> 42
|
// func = \_ _ -> 42
|
||||||
|
|
||||||
func
|
// func
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"*, * -> Int",
|
// "*, * -> Int",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_3_arg_closure() {
|
// fn def_3_arg_closure() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
f = \_ _ _ -> "test!"
|
// f = \_ _ _ -> "test!"
|
||||||
|
|
||||||
f
|
// f
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"*, *, * -> String",
|
// "*, *, * -> String",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_multiple_functions() {
|
// fn def_multiple_functions() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
a = \_ _ _ -> "test!"
|
// a = \_ _ _ -> "test!"
|
||||||
|
|
||||||
b = a
|
// b = a
|
||||||
|
|
||||||
b
|
// b
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"*, *, * -> String",
|
// "*, *, * -> String",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_multiple_strings() {
|
// fn def_multiple_strings() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
a = "test!"
|
// a = "test!"
|
||||||
|
|
||||||
b = a
|
// b = a
|
||||||
|
|
||||||
b
|
// b
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"Str",
|
// "Str",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn def_multiple_nums() {
|
// fn def_multiple_nums() {
|
||||||
infer_eq(
|
// infer_eq(
|
||||||
indoc!(
|
// indoc!(
|
||||||
r#"
|
// r#"
|
||||||
c = b
|
// c = b
|
||||||
|
|
||||||
b = a
|
// b = a
|
||||||
|
|
||||||
a = 42
|
// a = 42
|
||||||
|
|
||||||
c
|
// c
|
||||||
"#
|
// "#
|
||||||
),
|
// ),
|
||||||
"Int",
|
// "Int",
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
// // CALLING FUNCTIONS
|
// // CALLING FUNCTIONS
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ mod test_parse {
|
||||||
use roc::parse::ast::CommentOrNewline::*;
|
use roc::parse::ast::CommentOrNewline::*;
|
||||||
use roc::parse::ast::Expr::{self, *};
|
use roc::parse::ast::Expr::{self, *};
|
||||||
use roc::parse::ast::Pattern::*;
|
use roc::parse::ast::Pattern::*;
|
||||||
use roc::parse::ast::{Attempting, Spaceable};
|
use roc::parse::ast::{Attempting, Def, Spaceable};
|
||||||
use roc::parse::parser::{Fail, FailReason};
|
use roc::parse::parser::{Fail, FailReason};
|
||||||
use roc::region::{Located, Region};
|
use roc::region::{Located, Region};
|
||||||
use std::{f64, i64};
|
use std::{f64, i64};
|
||||||
|
@ -635,6 +635,17 @@ mod test_parse {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_def() {
|
fn basic_def() {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
||||||
|
let def = Def::BodyOnly(
|
||||||
|
Located::new(0, 0, 0, 1, Identifier("x")),
|
||||||
|
arena.alloc(Located::new(0, 0, 2, 3, Int("5"))),
|
||||||
|
);
|
||||||
|
let defs = bumpalo::vec![in &arena; (Vec::new_in(&arena).into_bump_slice(), def)];
|
||||||
|
let ret = Expr::SpaceBefore(arena.alloc(Int("42")), newlines.into_bump_slice());
|
||||||
|
let loc_ret = Located::new(2, 2, 0, 2, ret);
|
||||||
|
let expected = Defs(arena.alloc((defs, loc_ret)));
|
||||||
|
|
||||||
assert_parses_to(
|
assert_parses_to(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -643,7 +654,7 @@ mod test_parse {
|
||||||
42
|
42
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
Str(""),
|
expected,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue