attempts at parsing

This commit is contained in:
Folkert 2022-05-25 20:30:43 +02:00
parent 72518bca9c
commit d174cb72ae
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
2 changed files with 408 additions and 18 deletions

View file

@ -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)]

View file

@ -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 {