From d174cb72aea5407db2ae247ccd7a68c02eeb9d42 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 25 May 2022 20:30:43 +0200 Subject: [PATCH] attempts at parsing --- compiler/parse/src/ast.rs | 56 +++++- compiler/parse/src/expr.rs | 370 +++++++++++++++++++++++++++++++++++-- 2 files changed, 408 insertions(+), 18 deletions(-) diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index ddd668ca51..67254e1f38 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -4,7 +4,7 @@ use crate::header::{AppHeader, HostedHeader, InterfaceHeader, PlatformHeader}; use crate::ident::Ident; use bumpalo::collections::{String, Vec}; 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_region::all::{Loc, Position, Region}; @@ -334,7 +334,7 @@ pub enum ValueDef<'a> { Expect(&'a Loc>), } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct Defs<'a> { pub tags: std::vec::Vec, ValueDef<'a>>>, pub regions: std::vec::Vec, @@ -346,12 +346,62 @@ pub struct Defs<'a> { } impl<'a> Defs<'a> { - pub fn defs(&self) -> impl Iterator, &ValueDef<'a>>> { + pub fn defs(&self) -> impl Iterator, &ValueDef<'a>>> { self.tags.iter().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()]), }) } + + pub fn last(&self) -> Option, &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, 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)] diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index 25d68f7842..6a22744b8a 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -1,6 +1,6 @@ use crate::ast::{ - AssignedField, Collection, CommentOrNewline, Def, Derived, Expr, ExtractSpaces, Has, Pattern, - Spaceable, TypeAnnotation, TypeDef, TypeHeader, ValueDef, + AssignedField, Collection, CommentOrNewline, Def, Defs, Derived, Expr, ExtractSpaces, Has, + Pattern, Spaceable, TypeAnnotation, TypeDef, TypeHeader, ValueDef, }; use crate::blankspace::{ 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>], } +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])> = 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>] = &[]; + 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>] = &[]; + 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>( options: ExprParseOptions, start_column: u32, @@ -1309,6 +1609,32 @@ fn finish_parsing_ability_def<'a>( arena: &'a Bump, state: State<'a>, ) -> ParseResult<'a, &'a Loc>, 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>], + loc_has: Loc>, + arena: &'a Bump, + state: State<'a>, +) -> ParseResult<'a, (TypeDef<'a>, Region), EExpr<'a>> { let mut demands = Vec::with_capacity_in(2, arena); 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 = Def::Type(TypeDef::Ability { + let type_def = TypeDef::Ability { header: TypeHeader { name, vars: args }, loc_has, members: demands.into_bump_slice(), - }); + }; - 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)) + Ok((MadeProgress, (type_def, def_region), state)) } 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>>, EExpr<'a>> { move |arena, state: State<'a>| { let def_state = DefState {