Merge pull request #1960 from rtfeldman/joshuawarner32/refactor-extract-Collection

Introduce Collection as a general abstraction in the ast
This commit is contained in:
Folkert de Vries 2021-11-12 10:22:21 +01:00 committed by GitHub
commit 35a74a1fe4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 87 additions and 64 deletions

View File

@ -395,7 +395,8 @@ pub fn to_type2<'a>(
Type2::Variable(var)
}
Record { fields, ext, .. } => {
let field_types_map = can_assigned_fields(env, scope, references, fields, region);
let field_types_map =
can_assigned_fields(env, scope, references, &fields.items, region);
let field_types = PoolVec::with_capacity(field_types_map.len() as u32, env.pool);

View File

@ -389,7 +389,7 @@ fn can_annotation_help(
Record { fields, ext, .. } => {
let field_types = can_assigned_fields(
env,
fields,
&fields.items,
region,
scope,
var_store,

View File

@ -1,6 +1,6 @@
use crate::spaces::{fmt_comments_only, fmt_spaces, newline, NewlineAt, INDENT};
use bumpalo::collections::String;
use roc_parse::ast::{AssignedField, Expr, Tag, TypeAnnotation};
use roc_parse::ast::{AssignedField, Collection, Expr, Tag, TypeAnnotation};
use roc_region::all::Located;
/// Does an AST node need parens around it?
@ -183,17 +183,13 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> {
Apply(_, _, args) => args.iter().any(|loc_arg| loc_arg.value.is_multiline()),
As(lhs, _, rhs) => lhs.value.is_multiline() || rhs.value.is_multiline(),
Record {
fields,
ext,
final_comments: _,
} => {
Record { fields, ext } => {
match ext {
Some(ann) if ann.value.is_multiline() => return true,
_ => {}
}
fields.iter().any(|field| field.value.is_multiline())
fields.items.iter().any(|field| field.value.is_multiline())
}
TagUnion {
@ -296,16 +292,19 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> {
}
Record {
fields,
ext,
fields:
Collection {
items,
final_comments,
},
ext,
} => {
format_sequence!(
buf,
indent,
'{',
'}',
fields,
items,
final_comments,
newlines,
AssignedField

View File

@ -293,16 +293,12 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) ->
Apply { name, parts }
}
ast::TypeAnnotation::Record {
fields,
ext,
final_comments: _,
} => {
ast::TypeAnnotation::Record { fields, ext } => {
let mut doc_fields = Vec::new();
let mut any_fields_include_private_tags = false;
for field in fields {
for field in fields.items {
match record_field_to_doc(in_func_type_ann, field.value) {
None => {
any_fields_include_private_tags = true;

View File

@ -2630,7 +2630,7 @@ fn parse_header<'a>(
std::str::from_utf8_unchecked(&src_bytes[..chomped])
};
let packages = header.packages.into_bump_slice();
let packages = header.packages.items;
let info = HeaderInfo {
loc_name: Located {

View File

@ -5,6 +5,28 @@ use bumpalo::Bump;
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
use roc_region::all::{Loc, Position, Region};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Collection<'a, T> {
pub items: &'a [T],
pub final_comments: &'a [CommentOrNewline<'a>],
}
impl<'a, T> Collection<'a, T> {
pub fn empty() -> Collection<'a, T> {
Collection {
items: &[],
final_comments: &[],
}
}
pub fn with_items(items: &'a [T]) -> Collection<'a, T> {
Collection {
items,
final_comments: &[],
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Module<'a> {
Interface { header: InterfaceHeader<'a> },
@ -231,11 +253,11 @@ 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>],
// final_comments: &'a [CommentOrNewline<'a>],
},
/// A tag union, e.g. `[

View File

@ -2149,7 +2149,7 @@ 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>> {
move |arena, state| {
let (_, (parsed_elems, final_comments), state) = collection_trailing_sep_e!(
let (_, elements, 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
@ -2164,15 +2164,15 @@ fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>>
)
.parse(arena, state)?;
let mut allocated = Vec::with_capacity_in(parsed_elems.len(), arena);
let mut allocated = Vec::with_capacity_in(elements.items.len(), arena);
for parsed_elem in parsed_elems {
allocated.push(&*arena.alloc(parsed_elem));
for parsed_elem in elements.items {
allocated.push(parsed_elem);
}
let expr = Expr::List {
items: allocated.into_bump_slice(),
final_comments,
final_comments: elements.final_comments,
};
Ok((MadeProgress, expr, state))

View File

@ -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, *};
@ -81,7 +81,7 @@ 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 packages: Collection<'a, Loc<PackageEntry<'a>>>,
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
pub to: Loc<To<'a>>,
@ -146,7 +146,7 @@ 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 packages: Collection<'a, Loc<PackageEntry<'a>>>,
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
pub effects: Effects<'a>,

View File

@ -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,
@ -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,7 +213,7 @@ 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
@ -229,7 +229,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
let header = AppHeader {
name,
packages: package_entries,
packages,
imports,
provides: provides.entries,
to: provides.to,
@ -582,11 +582,9 @@ 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>],
final_comments: &'a [CommentOrNewline<'a>],
}
#[inline(always)]
@ -615,12 +613,14 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
PackageEntry::SpaceBefore
)
),
|((before_packages_keyword, after_packages_keyword), (entries, final_comments))| {
|((before_packages_keyword, after_packages_keyword), entries): (
(_, _),
Collection<'a, _>
)| {
Packages {
entries,
before_packages_keyword,
after_packages_keyword,
final_comments,
}
}
)

View File

@ -1300,7 +1300,12 @@ macro_rules! collection_trailing_sep_e {
}
}
Ok((MadeProgress, (parsed_elems, final_comments), state))
let collection = $crate::ast::Collection {
items: parsed_elems.into_bump_slice(),
final_comments,
};
Ok((MadeProgress, collection, state))
}
)
};

View File

@ -316,7 +316,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),
@ -332,9 +332,9 @@ fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRec
.parse(arena, state)?;
// TODO
let _unused = final_comments;
let _unused = fields.final_comments;
let result = Pattern::RecordDestructure(fields.into_bump_slice());
let result = Pattern::RecordDestructure(fields.items);
Ok((MadeProgress, result, state))
}

View File

@ -1,4 +1,4 @@
use crate::ast::{AssignedField, Tag, TypeAnnotation};
use crate::ast::{AssignedField, Collection, Tag, TypeAnnotation};
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
use crate::keyword;
use crate::parser::{
@ -18,7 +18,7 @@ pub fn located_help<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotati
#[inline(always)]
fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TTagUnion<'a>> {
move |arena, state| {
let (_, (tags, final_comments), state) = collection_trailing_sep_e!(
let (_, tags, state) = collection_trailing_sep_e!(
word1(b'[', TTagUnion::Open),
loc!(tag_type(min_indent)),
word1(b',', TTagUnion::End),
@ -37,9 +37,9 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TT
.parse(arena, state)?;
let result = TypeAnnotation::TagUnion {
tags: tags.into_bump_slice(),
tags: tags.items,
ext,
final_comments,
final_comments: tags.final_comments,
};
Ok((MadeProgress, result, state))
@ -267,7 +267,7 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TReco
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),
loc!(record_type_field(min_indent)),
@ -286,9 +286,11 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TReco
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?;
let result = Record {
fields: fields.into_bump_slice(),
fields: Collection {
items: fields.items,
final_comments: fields.final_comments,
},
ext,
final_comments,
};
Ok((MadeProgress, result, state))

View File

@ -23,7 +23,9 @@ mod test_parse {
use roc_parse::ast::Pattern::{self, *};
use roc_parse::ast::StrLiteral::{self, *};
use roc_parse::ast::StrSegment::*;
use roc_parse::ast::{self, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch};
use roc_parse::ast::{
self, Collection, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch,
};
use roc_parse::header::{
AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To,
@ -2281,9 +2283,8 @@ mod test_parse {
6,
TypeAnnotation::SpaceBefore(
&TypeAnnotation::Record {
fields: &[],
fields: Collection::empty(),
ext: None,
final_comments: &[],
},
&[Newline],
),
@ -2320,9 +2321,8 @@ mod test_parse {
6,
TypeAnnotation::SpaceBefore(
&TypeAnnotation::Record {
fields: &[],
fields: Collection::empty(),
ext: None,
final_comments: &[],
},
&[LineComment(" comment")],
),
@ -3091,7 +3091,7 @@ mod test_parse {
#[test]
fn empty_app_header() {
let arena = Bump::new();
let packages = Vec::new_in(&arena);
let packages = Collection::empty();
let imports = Vec::new_in(&arena);
let provides = Vec::new_in(&arena);
let module_name = StrLiteral::PlainLine("test-app");
@ -3131,7 +3131,7 @@ mod test_parse {
use PackageOrPath::Path;
let arena = Bump::new();
let packages = Vec::new_in(&arena);
let packages = Collection::empty();
let imports = Vec::new_in(&arena);
let provides = Vec::new_in(&arena);
let module_name = StrLiteral::PlainLine("test-app");
@ -3180,7 +3180,7 @@ mod test_parse {
};
let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry);
let arena = Bump::new();
let packages = bumpalo::vec![in &arena; loc_pkg_entry];
let packages = Collection::with_items(arena.alloc([loc_pkg_entry]));
let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena));
let loc_import = Located::new(2, 2, 14, 25, import);
let imports = bumpalo::vec![in &arena; loc_import];
@ -3236,7 +3236,7 @@ mod test_parse {
};
let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry);
let arena = Bump::new();
let packages = bumpalo::vec![in &arena; loc_pkg_entry];
let packages = Collection::with_items(arena.alloc([loc_pkg_entry]));
let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena));
let loc_import = Located::new(2, 2, 14, 25, import);
let imports = bumpalo::vec![in &arena; loc_import];
@ -3309,9 +3309,8 @@ mod test_parse {
ann: Located::at(
region2,
TypeAnnotation::Record {
fields: &[],
fields: Collection::empty(),
ext: None,
final_comments: &[],
},
),
},
@ -3324,7 +3323,7 @@ mod test_parse {
name: Located::new(0, 0, 9, 23, pkg_name),
requires,
exposes: Vec::new_in(&arena),
packages: Vec::new_in(&arena),
packages: Collection::empty(),
imports: Vec::new_in(&arena),
provides: Vec::new_in(&arena),
effects,
@ -3367,7 +3366,7 @@ mod test_parse {
};
let loc_pkg_entry = Located::new(3, 3, 15, 27, pkg_entry);
let arena = Bump::new();
let packages = bumpalo::vec![in &arena; loc_pkg_entry];
let packages = Collection::with_items(arena.alloc([loc_pkg_entry]));
let imports = Vec::new_in(&arena);
let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost"));
let provides = bumpalo::vec![in &arena; provide_entry];
@ -3395,9 +3394,8 @@ mod test_parse {
ann: Located::at(
region2,
TypeAnnotation::Record {
fields: &[],
fields: Collection::empty(),
ext: None,
final_comments: &[],
},
),
},