mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Merge remote-tracking branch 'origin/trunk' into single-quote-literal
This commit is contained in:
commit
f7c0e2ef19
634 changed files with 47014 additions and 21117 deletions
|
@ -1,17 +1,76 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use crate::header::{AppHeader, ImportsEntry, InterfaceHeader, PlatformHeader, TypedIdent};
|
||||
use crate::header::{AppHeader, HostedHeader, InterfaceHeader, PlatformHeader};
|
||||
use crate::ident::Ident;
|
||||
use bumpalo::collections::{String, Vec};
|
||||
use bumpalo::Bump;
|
||||
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Spaces<'a, T> {
|
||||
pub before: &'a [CommentOrNewline<'a>],
|
||||
pub item: T,
|
||||
pub after: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Spaced<'a, T> {
|
||||
Item(T),
|
||||
|
||||
// Spaces
|
||||
SpaceBefore(&'a Spaced<'a, T>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a Spaced<'a, T>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
impl<'a, T: Debug> Debug for Spaced<'a, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Item(item) => item.fmt(f),
|
||||
Self::SpaceBefore(item, space) => f
|
||||
.debug_tuple("SpaceBefore")
|
||||
.field(item)
|
||||
.field(space)
|
||||
.finish(),
|
||||
Self::SpaceAfter(item, space) => f
|
||||
.debug_tuple("SpaceAfter")
|
||||
.field(item)
|
||||
.field(space)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ExtractSpaces<'a>: Sized + Copy {
|
||||
type Item;
|
||||
fn extract_spaces(&self) -> Spaces<'a, Self::Item>;
|
||||
}
|
||||
|
||||
impl<'a, T: ExtractSpaces<'a>> ExtractSpaces<'a> for &'a T {
|
||||
type Item = T::Item;
|
||||
fn extract_spaces(&self) -> Spaces<'a, Self::Item> {
|
||||
(*self).extract_spaces()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ExtractSpaces<'a>> ExtractSpaces<'a> for Loc<T> {
|
||||
type Item = T::Item;
|
||||
fn extract_spaces(&self) -> Spaces<'a, Self::Item> {
|
||||
let spaces = self.value.extract_spaces();
|
||||
Spaces {
|
||||
before: spaces.before,
|
||||
item: spaces.item,
|
||||
after: spaces.after,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Module<'a> {
|
||||
Interface { header: InterfaceHeader<'a> },
|
||||
App { header: AppHeader<'a> },
|
||||
Platform { header: PlatformHeader<'a> },
|
||||
Hosted { header: HostedHeader<'a> },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
@ -118,6 +177,10 @@ pub enum Expr<'a> {
|
|||
GlobalTag(&'a str),
|
||||
PrivateTag(&'a str),
|
||||
|
||||
// Reference to an opaque type, e.g. $Opaq
|
||||
// TODO(opaques): $->@ in the above comment
|
||||
OpaqueRef(&'a str),
|
||||
|
||||
// Pattern Matching
|
||||
Closure(&'a [Loc<Pattern<'a>>], &'a Loc<Expr<'a>>),
|
||||
/// Multiple defs in a row
|
||||
|
@ -169,6 +232,22 @@ pub struct PrecedenceConflict<'a> {
|
|||
pub expr: &'a Loc<Expr<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct TypeHeader<'a> {
|
||||
pub name: Loc<&'a str>,
|
||||
pub vars: &'a [Loc<Pattern<'a>>],
|
||||
}
|
||||
|
||||
impl<'a> TypeHeader<'a> {
|
||||
pub fn region(&self) -> Region {
|
||||
Region::across_all(
|
||||
[self.name.region]
|
||||
.iter()
|
||||
.chain(self.vars.iter().map(|v| &v.region)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Def<'a> {
|
||||
// TODO in canonicalization, validate the pattern; only certain patterns
|
||||
|
@ -180,11 +259,16 @@ pub enum Def<'a> {
|
|||
///
|
||||
/// Foo : Bar Baz
|
||||
Alias {
|
||||
name: Loc<&'a str>,
|
||||
vars: &'a [Loc<Pattern<'a>>],
|
||||
header: TypeHeader<'a>,
|
||||
ann: Loc<TypeAnnotation<'a>>,
|
||||
},
|
||||
|
||||
/// An opaque type, wrapping its inner type. E.g. Age := U64.
|
||||
Opaque {
|
||||
header: TypeHeader<'a>,
|
||||
typ: Loc<TypeAnnotation<'a>>,
|
||||
},
|
||||
|
||||
// TODO in canonicalization, check to see if there are any newlines after the
|
||||
// annotation; if not, and if it's followed by a Body, then the annotation
|
||||
// applies to that expr! (TODO: verify that the pattern for both annotation and body match.)
|
||||
|
@ -209,6 +293,17 @@ pub enum Def<'a> {
|
|||
NotYetImplemented(&'static str),
|
||||
}
|
||||
|
||||
impl<'a> Def<'a> {
|
||||
pub fn unroll_spaces_before(&self) -> (&'a [CommentOrNewline<'a>], &Def) {
|
||||
let (spaces, def): (&'a [_], &Def) = match self {
|
||||
Def::SpaceBefore(def, spaces) => (spaces, def),
|
||||
def => (&[], def),
|
||||
};
|
||||
debug_assert!(!matches!(def, Def::SpaceBefore(_, _)));
|
||||
(spaces, def)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum TypeAnnotation<'a> {
|
||||
/// A function. The types of its arguments, then the type of its return value.
|
||||
|
@ -224,7 +319,7 @@ pub enum TypeAnnotation<'a> {
|
|||
As(
|
||||
&'a Loc<TypeAnnotation<'a>>,
|
||||
&'a [CommentOrNewline<'a>],
|
||||
&'a Loc<TypeAnnotation<'a>>,
|
||||
TypeHeader<'a>,
|
||||
),
|
||||
|
||||
Record {
|
||||
|
@ -323,6 +418,15 @@ impl<'a> CommentOrNewline<'a> {
|
|||
DocComment(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string_repr(&self) -> std::string::String {
|
||||
use CommentOrNewline::*;
|
||||
match self {
|
||||
Newline => "\n".to_owned(),
|
||||
LineComment(comment_str) => format!("#{}", comment_str),
|
||||
DocComment(comment_str) => format!("##{}", comment_str),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
@ -332,9 +436,12 @@ pub enum Pattern<'a> {
|
|||
|
||||
GlobalTag(&'a str),
|
||||
PrivateTag(&'a str),
|
||||
|
||||
OpaqueRef(&'a str),
|
||||
|
||||
Apply(&'a Loc<Pattern<'a>>, &'a [Loc<Pattern<'a>>]),
|
||||
|
||||
/// This is Loc<Pattern> rather than Loc<str> so we can record comments
|
||||
/// This is Located<Pattern> rather than Located<str> so we can record comments
|
||||
/// around the destructured names, e.g. { x ### x does stuff ###, y }
|
||||
/// In practice, these patterns will always be Identifier
|
||||
RecordDestructure(Collection<'a, Loc<Pattern<'a>>>),
|
||||
|
@ -385,6 +492,7 @@ impl<'a> Pattern<'a> {
|
|||
match ident {
|
||||
Ident::GlobalTag(string) => Pattern::GlobalTag(string),
|
||||
Ident::PrivateTag(string) => Pattern::PrivateTag(string),
|
||||
Ident::OpaqueRef(string) => Pattern::OpaqueRef(string),
|
||||
Ident::Access { module_name, parts } => {
|
||||
if parts.len() == 1 {
|
||||
// This is valid iff there is no module.
|
||||
|
@ -643,6 +751,15 @@ pub trait Spaceable<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Spaceable<'a> for Spaced<'a, T> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Spaced::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Spaced::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for Expr<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Expr::SpaceBefore(self, spaces)
|
||||
|
@ -670,24 +787,6 @@ impl<'a> Spaceable<'a> for TypeAnnotation<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for ImportsEntry<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
ImportsEntry::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
ImportsEntry::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for TypedIdent<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
TypedIdent::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
TypedIdent::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Val> Spaceable<'a> for AssignedField<'a, Val> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
AssignedField::SpaceBefore(self, spaces)
|
||||
|
@ -729,4 +828,123 @@ impl<'a> Expr<'a> {
|
|||
value: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_tag(&self) -> bool {
|
||||
matches!(self, Expr::GlobalTag(_) | Expr::PrivateTag(_))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_extract_spaces {
|
||||
($t:ident $(< $($generic_args:ident),* >)?) => {
|
||||
|
||||
impl<'a, $($($generic_args: Copy),*)?> ExtractSpaces<'a> for $t<'a, $($($generic_args),*)?> {
|
||||
type Item = Self;
|
||||
fn extract_spaces(&self) -> Spaces<'a, Self::Item> {
|
||||
match self {
|
||||
$t::SpaceBefore(item, before) => {
|
||||
match item {
|
||||
$t::SpaceBefore(_, _) => todo!(),
|
||||
$t::SpaceAfter(item, after) => {
|
||||
Spaces {
|
||||
before,
|
||||
item: **item,
|
||||
after,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Spaces {
|
||||
before,
|
||||
item: **item,
|
||||
after: &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
$t::SpaceAfter(item, after) => {
|
||||
match item {
|
||||
$t::SpaceBefore(item, before) => {
|
||||
Spaces {
|
||||
before,
|
||||
item: **item,
|
||||
after,
|
||||
}
|
||||
}
|
||||
$t::SpaceAfter(_, _) => todo!(),
|
||||
_ => {
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: **item,
|
||||
after,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: *self,
|
||||
after: &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_extract_spaces!(Expr);
|
||||
impl_extract_spaces!(Pattern);
|
||||
impl_extract_spaces!(Tag);
|
||||
impl_extract_spaces!(AssignedField<T>);
|
||||
|
||||
impl<'a, T: Copy> ExtractSpaces<'a> for Spaced<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn extract_spaces(&self) -> Spaces<'a, T> {
|
||||
match self {
|
||||
Spaced::SpaceBefore(item, before) => match item {
|
||||
Spaced::SpaceBefore(_, _) => todo!(),
|
||||
Spaced::SpaceAfter(item, after) => {
|
||||
if let Spaced::Item(item) = item {
|
||||
Spaces {
|
||||
before,
|
||||
item: *item,
|
||||
after,
|
||||
}
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
Spaced::Item(item) => Spaces {
|
||||
before,
|
||||
item: *item,
|
||||
after: &[],
|
||||
},
|
||||
},
|
||||
Spaced::SpaceAfter(item, after) => match item {
|
||||
Spaced::SpaceBefore(item, before) => {
|
||||
if let Spaced::Item(item) = item {
|
||||
Spaces {
|
||||
before,
|
||||
item: *item,
|
||||
after,
|
||||
}
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
Spaced::SpaceAfter(_, _) => todo!(),
|
||||
Spaced::Item(item) => Spaces {
|
||||
before: &[],
|
||||
item: *item,
|
||||
after,
|
||||
},
|
||||
},
|
||||
Spaced::Item(item) => Spaces {
|
||||
before: &[],
|
||||
item: *item,
|
||||
after: &[],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue