mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
attempts at parsing
This commit is contained in:
parent
72518bca9c
commit
d174cb72ae
2 changed files with 408 additions and 18 deletions
|
@ -4,7 +4,7 @@ use crate::header::{AppHeader, HostedHeader, InterfaceHeader, PlatformHeader};
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use bumpalo::collections::{String, Vec};
|
use bumpalo::collections::{String, Vec};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_collections::soa::{EitherIndex, Slice};
|
use roc_collections::soa::{EitherIndex, Index, Slice};
|
||||||
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
||||||
use roc_region::all::{Loc, Position, Region};
|
use roc_region::all::{Loc, Position, Region};
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ pub enum ValueDef<'a> {
|
||||||
Expect(&'a Loc<Expr<'a>>),
|
Expect(&'a Loc<Expr<'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
pub struct Defs<'a> {
|
pub struct Defs<'a> {
|
||||||
pub tags: std::vec::Vec<EitherIndex<TypeDef<'a>, ValueDef<'a>>>,
|
pub tags: std::vec::Vec<EitherIndex<TypeDef<'a>, ValueDef<'a>>>,
|
||||||
pub regions: std::vec::Vec<Region>,
|
pub regions: std::vec::Vec<Region>,
|
||||||
|
@ -346,12 +346,62 @@ pub struct Defs<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Defs<'a> {
|
impl<'a> Defs<'a> {
|
||||||
pub fn defs(&self) -> impl Iterator<Item = Result<&TypeDef<'a>, &ValueDef<'a>>> {
|
pub fn defs<I>(&self) -> impl Iterator<Item = Result<&TypeDef<'a>, &ValueDef<'a>>> {
|
||||||
self.tags.iter().map(|tag| match tag.split() {
|
self.tags.iter().map(|tag| match tag.split() {
|
||||||
Ok(type_index) => Ok(&self.type_defs[type_index.index()]),
|
Ok(type_index) => Ok(&self.type_defs[type_index.index()]),
|
||||||
Err(value_index) => Err(&self.value_defs[value_index.index()]),
|
Err(value_index) => Err(&self.value_defs[value_index.index()]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn last(&self) -> Option<Result<&TypeDef<'a>, &ValueDef<'a>>> {
|
||||||
|
self.tags.last().map(|tag| match tag.split() {
|
||||||
|
Ok(type_index) => Ok(&self.type_defs[type_index.index()]),
|
||||||
|
Err(value_index) => Err(&self.value_defs[value_index.index()]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// NOTE assumes the def itself is pushed already!
|
||||||
|
fn push_def_help(
|
||||||
|
&mut self,
|
||||||
|
tag: EitherIndex<TypeDef<'a>, ValueDef<'a>>,
|
||||||
|
region: Region,
|
||||||
|
spaces_before: &[CommentOrNewline<'a>],
|
||||||
|
spaces_after: &[CommentOrNewline<'a>],
|
||||||
|
) {
|
||||||
|
self.tags.push(tag);
|
||||||
|
|
||||||
|
self.regions.push(region);
|
||||||
|
|
||||||
|
let before = Slice::extend_new(&mut self.spaces, spaces_before.iter().copied());
|
||||||
|
self.space_before.push(before);
|
||||||
|
|
||||||
|
let after = Slice::extend_new(&mut self.spaces, spaces_after.iter().copied());
|
||||||
|
self.space_after.push(after);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_value_def(
|
||||||
|
&mut self,
|
||||||
|
value_def: ValueDef<'a>,
|
||||||
|
region: Region,
|
||||||
|
spaces_before: &[CommentOrNewline<'a>],
|
||||||
|
spaces_after: &[CommentOrNewline<'a>],
|
||||||
|
) {
|
||||||
|
let value_def_index = Index::push_new(&mut self.value_defs, value_def);
|
||||||
|
let tag = EitherIndex::from_right(value_def_index);
|
||||||
|
self.push_def_help(tag, region, spaces_before, spaces_after)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_type_def(
|
||||||
|
&mut self,
|
||||||
|
type_def: TypeDef<'a>,
|
||||||
|
region: Region,
|
||||||
|
spaces_before: &[CommentOrNewline<'a>],
|
||||||
|
spaces_after: &[CommentOrNewline<'a>],
|
||||||
|
) {
|
||||||
|
let type_def_index = Index::push_new(&mut self.type_defs, type_def);
|
||||||
|
let tag = EitherIndex::from_left(type_def_index);
|
||||||
|
self.push_def_help(tag, region, spaces_before, spaces_after)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
AssignedField, Collection, CommentOrNewline, Def, Derived, Expr, ExtractSpaces, Has, Pattern,
|
AssignedField, Collection, CommentOrNewline, Def, Defs, Derived, Expr, ExtractSpaces, Has,
|
||||||
Spaceable, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
Pattern, Spaceable, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{
|
use crate::blankspace::{
|
||||||
space0_after_e, space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
space0_after_e, space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
||||||
|
@ -811,6 +811,306 @@ struct DefState<'a> {
|
||||||
spaces_after: &'a [CommentOrNewline<'a>],
|
spaces_after: &'a [CommentOrNewline<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_toplevel_defs_end<'a>(
|
||||||
|
options: ExprParseOptions,
|
||||||
|
start_column: u32,
|
||||||
|
mut defs: Defs<'a>,
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
) -> ParseResult<'a, Defs<'a>, EExpr<'a>> {
|
||||||
|
let min_indent = start_column;
|
||||||
|
let initial = state.clone();
|
||||||
|
|
||||||
|
let mut spaces_before_current = &[] as &[_];
|
||||||
|
|
||||||
|
let state = match space0_e(min_indent, EExpr::IndentStart).parse(arena, state) {
|
||||||
|
Err((MadeProgress, _, s)) => {
|
||||||
|
return Err((MadeProgress, EExpr::DefMissingFinalExpr(s.pos()), s));
|
||||||
|
}
|
||||||
|
Ok((_, spaces, state)) => {
|
||||||
|
spaces_before_current = spaces;
|
||||||
|
state
|
||||||
|
}
|
||||||
|
Err((NoProgress, _, state)) => state,
|
||||||
|
};
|
||||||
|
|
||||||
|
let start = state.pos();
|
||||||
|
let column = state.column();
|
||||||
|
|
||||||
|
match space0_after_e(
|
||||||
|
crate::pattern::loc_pattern_help(min_indent),
|
||||||
|
min_indent,
|
||||||
|
EPattern::IndentEnd,
|
||||||
|
)
|
||||||
|
.parse(arena, state.clone())
|
||||||
|
{
|
||||||
|
Err((NoProgress, _, _)) => {
|
||||||
|
match crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect)
|
||||||
|
.parse(arena, state)
|
||||||
|
{
|
||||||
|
Err((_, _, _)) => {
|
||||||
|
// a hacky way to get expression-based error messages. TODO fix this
|
||||||
|
Ok((NoProgress, defs, initial))
|
||||||
|
}
|
||||||
|
Ok((_, _, state)) => {
|
||||||
|
let parse_def_expr = space0_before_e(
|
||||||
|
move |a, s| parse_loc_expr(min_indent + 1, a, s),
|
||||||
|
min_indent,
|
||||||
|
EExpr::IndentEnd,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (_, loc_def_expr, state) = parse_def_expr.parse(arena, state)?;
|
||||||
|
|
||||||
|
let end = loc_def_expr.region.end();
|
||||||
|
let region = Region::new(start, end);
|
||||||
|
|
||||||
|
let value_def = ValueDef::Expect(arena.alloc(loc_def_expr));
|
||||||
|
defs.push_value_def(value_def, region, spaces_before_current, &[]);
|
||||||
|
|
||||||
|
parse_toplevel_defs_end(options, column, defs, arena, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err((MadeProgress, _, _)) => {
|
||||||
|
// a hacky way to get expression-based error messages. TODO fix this
|
||||||
|
Ok((NoProgress, defs, initial))
|
||||||
|
}
|
||||||
|
Ok((_, loc_pattern, state)) => {
|
||||||
|
// First let's check whether this is an ability definition.
|
||||||
|
let opt_tag_and_args: Option<(&str, Region, &[Loc<Pattern>])> = match loc_pattern.value
|
||||||
|
{
|
||||||
|
Pattern::Apply(
|
||||||
|
Loc {
|
||||||
|
value: Pattern::Tag(name),
|
||||||
|
region,
|
||||||
|
},
|
||||||
|
args,
|
||||||
|
) => Some((name, *region, args)),
|
||||||
|
Pattern::Tag(name) => Some((name, loc_pattern.region, &[])),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((name, name_region, args)) = opt_tag_and_args {
|
||||||
|
if let Ok((_, loc_has, state)) =
|
||||||
|
loc_has_parser(min_indent).parse(arena, state.clone())
|
||||||
|
{
|
||||||
|
let (_, (type_def, def_region), state) = finish_parsing_ability_def_help(
|
||||||
|
start_column,
|
||||||
|
Loc::at(name_region, name),
|
||||||
|
args,
|
||||||
|
loc_has,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, def_region, spaces_before_current, &[]);
|
||||||
|
|
||||||
|
return parse_toplevel_defs_end(options, column, defs, arena, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, this is a def or alias.
|
||||||
|
match operator().parse(arena, state) {
|
||||||
|
Ok((_, BinOp::Assignment, state)) => {
|
||||||
|
let parse_def_expr = space0_before_e(
|
||||||
|
move |a, s| parse_loc_expr(min_indent + 1, a, s),
|
||||||
|
min_indent,
|
||||||
|
EExpr::IndentEnd,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (_, loc_def_expr, state) = parse_def_expr.parse(arena, state)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let region = Region::span_across(&loc_pattern.region, &loc_def_expr.region);
|
||||||
|
|
||||||
|
if spaces_before_current.len() <= 1 {
|
||||||
|
match defs.last() {
|
||||||
|
Some((
|
||||||
|
before_ann_spaces,
|
||||||
|
Def::Value(ValueDef::Annotation(ann_pattern, ann_type)),
|
||||||
|
)) => {
|
||||||
|
return append_body_definition_help(
|
||||||
|
arena,
|
||||||
|
defs,
|
||||||
|
region,
|
||||||
|
before_ann_spaces,
|
||||||
|
spaces_before_current,
|
||||||
|
loc_pattern,
|
||||||
|
loc_def_expr,
|
||||||
|
ann_pattern,
|
||||||
|
ann_type,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Some((
|
||||||
|
before_ann_spaces,
|
||||||
|
Def::Type(TypeDef::Alias {
|
||||||
|
header,
|
||||||
|
ann: ann_type,
|
||||||
|
}),
|
||||||
|
)) => {
|
||||||
|
// This is a case like
|
||||||
|
// UserId x : [UserId Int]
|
||||||
|
// UserId x = UserId 42
|
||||||
|
// We optimistically parsed the first line as an alias; we now turn it
|
||||||
|
// into an annotation.
|
||||||
|
let loc_name =
|
||||||
|
arena.alloc(header.name.map(|x| Pattern::Tag(x)));
|
||||||
|
let ann_pattern = Pattern::Apply(loc_name, header.vars);
|
||||||
|
let vars_region =
|
||||||
|
Region::across_all(header.vars.iter().map(|v| &v.region));
|
||||||
|
let region_ann_pattern =
|
||||||
|
Region::span_across(&loc_name.region, &vars_region);
|
||||||
|
let loc_ann_pattern = Loc::at(region_ann_pattern, ann_pattern);
|
||||||
|
|
||||||
|
return append_body_definition_help(
|
||||||
|
arena,
|
||||||
|
defs,
|
||||||
|
region,
|
||||||
|
before_ann_spaces,
|
||||||
|
spaces_before_current,
|
||||||
|
loc_pattern,
|
||||||
|
loc_def_expr,
|
||||||
|
arena.alloc(loc_ann_pattern),
|
||||||
|
ann_type,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
defs.extend(last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the previous and current def can't be joined up
|
||||||
|
let mut loc_def = Loc::at(
|
||||||
|
region,
|
||||||
|
Def::Value(ValueDef::Body(
|
||||||
|
arena.alloc(loc_pattern),
|
||||||
|
&*arena.alloc(loc_def_expr),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if !spaces_before_current.is_empty() {
|
||||||
|
loc_def = arena
|
||||||
|
.alloc(loc_def.value)
|
||||||
|
.with_spaces_before(spaces_before_current, loc_def.region);
|
||||||
|
}
|
||||||
|
|
||||||
|
defs.push(arena.alloc(loc_def));
|
||||||
|
};
|
||||||
|
|
||||||
|
parse_toplevel_defs_end(options, column, defs, arena, state)
|
||||||
|
}
|
||||||
|
Ok((_, BinOp::IsAliasType, state)) => {
|
||||||
|
let (_, ann_type, state) =
|
||||||
|
alias_signature_with_space_before(min_indent + 1).parse(arena, state)?;
|
||||||
|
|
||||||
|
let region = Region::span_across(&loc_pattern.region, &ann_type.region);
|
||||||
|
|
||||||
|
// the previous and current def can't be joined up
|
||||||
|
match &loc_pattern.value {
|
||||||
|
Pattern::Apply(
|
||||||
|
Loc {
|
||||||
|
value: Pattern::Tag(name),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
alias_arguments,
|
||||||
|
) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: alias_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Alias {
|
||||||
|
header,
|
||||||
|
ann: ann_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
Pattern::Tag(name) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let pattern_arguments: &'a [Loc<Pattern<'a>>] = &[];
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: pattern_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Alias {
|
||||||
|
header,
|
||||||
|
ann: ann_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let value_def = ValueDef::Annotation(loc_pattern, ann_type);
|
||||||
|
defs.push_value_def(value_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
parse_toplevel_defs_end(options, column, defs, arena, state)
|
||||||
|
}
|
||||||
|
Ok((_, BinOp::IsOpaqueType, state)) => {
|
||||||
|
let (_, (signature, derived), state) =
|
||||||
|
opaque_signature_with_space_before(min_indent + 1).parse(arena, state)?;
|
||||||
|
|
||||||
|
let region = Region::span_across(&loc_pattern.region, &signature.region);
|
||||||
|
|
||||||
|
// the previous and current def can't be joined up
|
||||||
|
match &loc_pattern.value {
|
||||||
|
Pattern::Apply(
|
||||||
|
Loc {
|
||||||
|
value: Pattern::Tag(name),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
alias_arguments,
|
||||||
|
) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: alias_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Opaque {
|
||||||
|
header,
|
||||||
|
typ: signature,
|
||||||
|
derived,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
Pattern::Tag(name) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let pattern_arguments: &'a [Loc<Pattern<'a>>] = &[];
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: pattern_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Opaque {
|
||||||
|
header,
|
||||||
|
typ: signature,
|
||||||
|
derived,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let value_def = ValueDef::Annotation(loc_pattern, signature);
|
||||||
|
defs.push_value_def(value_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
parse_toplevel_defs_end(options, column, defs, arena, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Ok((MadeProgress, defs, initial)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_defs_end<'a>(
|
fn parse_defs_end<'a>(
|
||||||
options: ExprParseOptions,
|
options: ExprParseOptions,
|
||||||
start_column: u32,
|
start_column: u32,
|
||||||
|
@ -1309,6 +1609,32 @@ fn finish_parsing_ability_def<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
) -> ParseResult<'a, &'a Loc<Def<'a>>, EExpr<'a>> {
|
) -> ParseResult<'a, &'a Loc<Def<'a>>, EExpr<'a>> {
|
||||||
|
let (_, (type_def, def_region), state) =
|
||||||
|
finish_parsing_ability_def_help(start_column, name, args, loc_has, arena, state)?;
|
||||||
|
|
||||||
|
let def = Def::Type(type_def);
|
||||||
|
|
||||||
|
let loc_def = &*(if spaces_before.is_empty() {
|
||||||
|
arena.alloc(Loc::at(def_region, def))
|
||||||
|
} else {
|
||||||
|
arena.alloc(
|
||||||
|
arena
|
||||||
|
.alloc(def)
|
||||||
|
.with_spaces_before(spaces_before, def_region),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok((MadeProgress, loc_def, state))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_parsing_ability_def_help<'a>(
|
||||||
|
start_column: u32,
|
||||||
|
name: Loc<&'a str>,
|
||||||
|
args: &'a [Loc<Pattern<'a>>],
|
||||||
|
loc_has: Loc<Has<'a>>,
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
) -> ParseResult<'a, (TypeDef<'a>, Region), EExpr<'a>> {
|
||||||
let mut demands = Vec::with_capacity_in(2, arena);
|
let mut demands = Vec::with_capacity_in(2, arena);
|
||||||
|
|
||||||
let min_indent_for_demand = start_column + 1;
|
let min_indent_for_demand = start_column + 1;
|
||||||
|
@ -1347,23 +1673,13 @@ fn finish_parsing_ability_def<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_region = Region::span_across(&name.region, &demands.last().unwrap().typ.region);
|
let def_region = Region::span_across(&name.region, &demands.last().unwrap().typ.region);
|
||||||
let def = Def::Type(TypeDef::Ability {
|
let type_def = TypeDef::Ability {
|
||||||
header: TypeHeader { name, vars: args },
|
header: TypeHeader { name, vars: args },
|
||||||
loc_has,
|
loc_has,
|
||||||
members: demands.into_bump_slice(),
|
members: demands.into_bump_slice(),
|
||||||
});
|
};
|
||||||
|
|
||||||
let loc_def = &*(if spaces_before.is_empty() {
|
Ok((MadeProgress, (type_def, def_region), state))
|
||||||
arena.alloc(Loc::at(def_region, def))
|
|
||||||
} else {
|
|
||||||
arena.alloc(
|
|
||||||
arena
|
|
||||||
.alloc(def)
|
|
||||||
.with_spaces_before(spaces_before, def_region),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok((MadeProgress, loc_def, state))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_parsing_ability<'a>(
|
fn finish_parsing_ability<'a>(
|
||||||
|
@ -1960,6 +2276,30 @@ fn assigned_expr_field_to_pattern_help<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toplevel_defs<'a>(min_indent: u32) -> impl Parser<'a, Defs<'a>, EExpr<'a>> {
|
||||||
|
move |arena, state: State<'a>| {
|
||||||
|
let (_, initial_space, state) =
|
||||||
|
space0_e(min_indent, EExpr::IndentEnd).parse(arena, state)?;
|
||||||
|
|
||||||
|
let start_column = state.column();
|
||||||
|
|
||||||
|
let options = ExprParseOptions {
|
||||||
|
accept_multi_backpassing: false,
|
||||||
|
check_for_arrow: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = Defs::default();
|
||||||
|
|
||||||
|
let (_, output, state) =
|
||||||
|
parse_toplevel_defs_end(options, start_column, output, arena, state)?;
|
||||||
|
|
||||||
|
let (_, final_space, state) =
|
||||||
|
space0_e(start_column, EExpr::IndentEnd).parse(arena, state)?;
|
||||||
|
|
||||||
|
Ok((MadeProgress, output, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn defs<'a>(min_indent: u32) -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, EExpr<'a>> {
|
pub fn defs<'a>(min_indent: u32) -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, EExpr<'a>> {
|
||||||
move |arena, state: State<'a>| {
|
move |arena, state: State<'a>| {
|
||||||
let def_state = DefState {
|
let def_state = DefState {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue