mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
WIP
This commit is contained in:
parent
743030fc99
commit
8a566dc339
260 changed files with 6344 additions and 2958 deletions
|
@ -394,6 +394,7 @@ pub enum StrLiteral<'a> {
|
|||
/// Values that can be tried, extracting success values or "returning early" on failure
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum TryTarget {
|
||||
// TODO: Remove when purity inference replaces Task fully
|
||||
/// Tasks suffixed with ! are `Task.await`ed
|
||||
Task,
|
||||
/// Results suffixed with ? are `Result.try`ed
|
||||
|
@ -841,6 +842,8 @@ pub enum ValueDef<'a> {
|
|||
IngestedFileImport(IngestedFileImport<'a>),
|
||||
|
||||
Stmt(&'a Loc<Expr<'a>>),
|
||||
|
||||
StmtAfterExpr,
|
||||
}
|
||||
|
||||
impl<'a> ValueDef<'a> {
|
||||
|
@ -1093,7 +1096,9 @@ impl<'a, 'b> Iterator for RecursiveValueDefIter<'a, 'b> {
|
|||
}
|
||||
}
|
||||
ValueDef::Stmt(loc_expr) => self.push_pending_from_expr(&loc_expr.value),
|
||||
ValueDef::Annotation(_, _) | ValueDef::IngestedFileImport(_) => {}
|
||||
ValueDef::Annotation(_, _)
|
||||
| ValueDef::IngestedFileImport(_)
|
||||
| ValueDef::StmtAfterExpr => {}
|
||||
}
|
||||
|
||||
self.index += 1;
|
||||
|
@ -1530,10 +1535,22 @@ impl ImplementsAbilities<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum FunctionArrow {
|
||||
/// ->
|
||||
Pure,
|
||||
/// =>
|
||||
Effectful,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum TypeAnnotation<'a> {
|
||||
/// A function. The types of its arguments, then the type of its return value.
|
||||
Function(&'a [Loc<TypeAnnotation<'a>>], &'a Loc<TypeAnnotation<'a>>),
|
||||
/// A function. The types of its arguments, the type of arrow used, then the type of its return value.
|
||||
Function(
|
||||
&'a [Loc<TypeAnnotation<'a>>],
|
||||
FunctionArrow,
|
||||
&'a Loc<TypeAnnotation<'a>>,
|
||||
),
|
||||
|
||||
/// Applying a type to some arguments (e.g. Map.Map String Int)
|
||||
Apply(&'a str, &'a str, &'a [Loc<TypeAnnotation<'a>>]),
|
||||
|
@ -2740,6 +2757,7 @@ impl<'a> Malformed for ValueDef<'a> {
|
|||
annotation,
|
||||
}) => path.is_malformed() || annotation.is_malformed(),
|
||||
ValueDef::Stmt(loc_expr) => loc_expr.is_malformed(),
|
||||
ValueDef::StmtAfterExpr => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2755,7 +2773,7 @@ impl<'a> Malformed for ModuleImportParams<'a> {
|
|||
impl<'a> Malformed for TypeAnnotation<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
TypeAnnotation::Function(args, ret) => {
|
||||
TypeAnnotation::Function(args, _arrow, ret) => {
|
||||
args.iter().any(|arg| arg.is_malformed()) || ret.is_malformed()
|
||||
}
|
||||
TypeAnnotation::Apply(_, _, args) => args.iter().any(|arg| arg.is_malformed()),
|
||||
|
|
|
@ -3120,7 +3120,7 @@ fn stmts_to_defs<'a>(
|
|||
break;
|
||||
}
|
||||
Stmt::Expr(e) => {
|
||||
if is_expr_suffixed(&e) && i + 1 < stmts.len() {
|
||||
if i + 1 < stmts.len() {
|
||||
defs.push_value_def(
|
||||
ValueDef::Stmt(arena.alloc(Loc::at(sp_stmt.item.region, e))),
|
||||
sp_stmt.item.region,
|
||||
|
@ -3128,10 +3128,6 @@ fn stmts_to_defs<'a>(
|
|||
&[],
|
||||
);
|
||||
} else {
|
||||
if last_expr.is_some() {
|
||||
return Err(EExpr::StmtAfterExpr(sp_stmt.item.region.start()));
|
||||
}
|
||||
|
||||
let e = if sp_stmt.before.is_empty() {
|
||||
e
|
||||
} else {
|
||||
|
@ -3142,10 +3138,6 @@ fn stmts_to_defs<'a>(
|
|||
}
|
||||
}
|
||||
Stmt::Backpassing(pats, call) => {
|
||||
if last_expr.is_some() {
|
||||
return Err(EExpr::StmtAfterExpr(sp_stmt.item.region.start()));
|
||||
}
|
||||
|
||||
if i + 1 >= stmts.len() {
|
||||
return Err(EExpr::BackpassContinue(sp_stmt.item.region.end()));
|
||||
}
|
||||
|
@ -3169,10 +3161,6 @@ fn stmts_to_defs<'a>(
|
|||
}
|
||||
|
||||
Stmt::TypeDef(td) => {
|
||||
if last_expr.is_some() {
|
||||
return Err(EExpr::StmtAfterExpr(sp_stmt.item.region.start()));
|
||||
}
|
||||
|
||||
if let (
|
||||
TypeDef::Alias {
|
||||
header,
|
||||
|
@ -3224,10 +3212,6 @@ fn stmts_to_defs<'a>(
|
|||
}
|
||||
}
|
||||
Stmt::ValueDef(vd) => {
|
||||
if last_expr.is_some() {
|
||||
return Err(EExpr::StmtAfterExpr(sp_stmt.item.region.start()));
|
||||
}
|
||||
|
||||
// NOTE: it shouldn't be necessary to convert ValueDef::Dbg into an expr, but
|
||||
// it turns out that ValueDef::Dbg exposes some bugs in the rest of the compiler.
|
||||
// In particular, it seems that the solver thinks the dbg expr must be a bool.
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::pattern::record_pattern_fields;
|
|||
use crate::state::State;
|
||||
use crate::string_literal::{self, parse_str_literal};
|
||||
use crate::type_annotation;
|
||||
use roc_module::ident::IdentSuffix;
|
||||
use roc_module::symbol::ModuleId;
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
|
||||
|
@ -1132,6 +1133,10 @@ impl<'a> ExposedName<'a> {
|
|||
pub fn as_str(&'a self) -> &'a str {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn is_effectful_fn(&self) -> bool {
|
||||
IdentSuffix::from_name(self.0).is_bang()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Keyword: Copy + Clone + Debug {
|
||||
|
@ -1255,7 +1260,7 @@ pub struct PlatformHeader<'a> {
|
|||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ImportsEntry<'a> {
|
||||
/// e.g. `Hello` or `Hello exposing [hello]` see roc-lang.org/examples/MultipleRocFiles/README.html
|
||||
/// e.g. `Hello` or `Hello exposing [hello]` see roc-lang.org/examples/MultipleRocFiles/README.html
|
||||
Module(
|
||||
ModuleName<'a>,
|
||||
Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
||||
|
|
|
@ -252,21 +252,27 @@ fn is_alnum(ch: char) -> bool {
|
|||
}
|
||||
|
||||
fn chomp_lowercase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
chomp_part(char::is_lowercase, is_alnum, buffer)
|
||||
chomp_part(char::is_lowercase, is_alnum, true, buffer)
|
||||
}
|
||||
|
||||
fn chomp_uppercase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
chomp_part(char::is_uppercase, is_alnum, buffer)
|
||||
chomp_part(char::is_uppercase, is_alnum, false, buffer)
|
||||
}
|
||||
|
||||
fn chomp_anycase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
chomp_part(char::is_alphabetic, is_alnum, buffer)
|
||||
use encode_unicode::CharExt;
|
||||
|
||||
let allow_bang =
|
||||
char::from_utf8_slice_start(buffer).map_or(false, |(leading, _)| leading.is_lowercase());
|
||||
|
||||
chomp_part(char::is_alphabetic, is_alnum, allow_bang, buffer)
|
||||
}
|
||||
|
||||
fn chomp_integer_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
chomp_part(
|
||||
|ch| char::is_ascii_digit(&ch),
|
||||
|ch| char::is_ascii_digit(&ch),
|
||||
false,
|
||||
buffer,
|
||||
)
|
||||
}
|
||||
|
@ -276,7 +282,12 @@ fn is_plausible_ident_continue(ch: char) -> bool {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn chomp_part<F, G>(leading_is_good: F, rest_is_good: G, buffer: &[u8]) -> Result<&str, Progress>
|
||||
fn chomp_part<F, G>(
|
||||
leading_is_good: F,
|
||||
rest_is_good: G,
|
||||
allow_bang: bool,
|
||||
buffer: &[u8],
|
||||
) -> Result<&str, Progress>
|
||||
where
|
||||
F: Fn(char) -> bool,
|
||||
G: Fn(char) -> bool,
|
||||
|
@ -296,6 +307,9 @@ where
|
|||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if rest_is_good(ch) {
|
||||
chomped += width;
|
||||
} else if allow_bang && ch == '!' {
|
||||
chomped += width;
|
||||
break;
|
||||
} else {
|
||||
// we're done
|
||||
break;
|
||||
|
@ -474,6 +488,16 @@ fn chomp_identifier_chain<'a>(
|
|||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if ch.is_alphabetic() || ch.is_ascii_digit() {
|
||||
chomped += width;
|
||||
} else if ch == '!' && !first_is_uppercase {
|
||||
chomped += width;
|
||||
|
||||
let value = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
||||
let ident = Ident::Access {
|
||||
module_name: "",
|
||||
parts: arena.alloc([Accessor::RecordField(value)]),
|
||||
};
|
||||
|
||||
return Ok((chomped as u32, ident));
|
||||
} else {
|
||||
// we're done
|
||||
break;
|
||||
|
|
|
@ -439,6 +439,7 @@ impl<'a> Normalize<'a> for ValueDef<'a> {
|
|||
IngestedFileImport(ingested_file_import.normalize(arena))
|
||||
}
|
||||
Stmt(loc_expr) => Stmt(arena.alloc(loc_expr.normalize(arena))),
|
||||
StmtAfterExpr => StmtAfterExpr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -881,8 +882,9 @@ impl<'a> Normalize<'a> for Pattern<'a> {
|
|||
impl<'a> Normalize<'a> for TypeAnnotation<'a> {
|
||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
TypeAnnotation::Function(a, b) => TypeAnnotation::Function(
|
||||
TypeAnnotation::Function(a, arrow, b) => TypeAnnotation::Function(
|
||||
arena.alloc(a.normalize(arena)),
|
||||
arrow,
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
TypeAnnotation::Apply(a, b, c) => TypeAnnotation::Apply(a, b, c.normalize(arena)),
|
||||
|
@ -1071,7 +1073,6 @@ impl<'a> Normalize<'a> for EExpr<'a> {
|
|||
EExpr::IndentEnd(_pos) => EExpr::IndentEnd(Position::zero()),
|
||||
EExpr::UnexpectedComma(_pos) => EExpr::UnexpectedComma(Position::zero()),
|
||||
EExpr::UnexpectedTopLevelExpr(_pos) => EExpr::UnexpectedTopLevelExpr(Position::zero()),
|
||||
EExpr::StmtAfterExpr(_pos) => EExpr::StmtAfterExpr(Position::zero()),
|
||||
EExpr::RecordUpdateOldBuilderField(_pos) => {
|
||||
EExpr::RecordUpdateOldBuilderField(Region::zero())
|
||||
}
|
||||
|
|
|
@ -303,7 +303,6 @@ pub enum EExpr<'a> {
|
|||
Start(Position),
|
||||
End(Position),
|
||||
BadExprEnd(Position),
|
||||
StmtAfterExpr(Position),
|
||||
Space(BadInputError, Position),
|
||||
|
||||
Dot(Position),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ast::{
|
||||
AbilityImpls, AssignedField, CommentOrNewline, Expr, ImplementsAbilities, ImplementsAbility,
|
||||
ImplementsClause, Pattern, Spaceable, Spaced, Tag, TypeAnnotation, TypeHeader,
|
||||
AbilityImpls, AssignedField, CommentOrNewline, Expr, FunctionArrow, ImplementsAbilities,
|
||||
ImplementsAbility, ImplementsClause, Pattern, Spaceable, Spaced, Tag, TypeAnnotation,
|
||||
TypeHeader,
|
||||
};
|
||||
use crate::blankspace::{
|
||||
space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
||||
|
@ -594,16 +595,23 @@ fn expression<'a>(
|
|||
],
|
||||
))
|
||||
.trace("type_annotation:expression:rest_args"),
|
||||
skip_second(
|
||||
and(
|
||||
space0_e(EType::TIndentStart),
|
||||
two_bytes(b'-', b'>', EType::TStart),
|
||||
one_of![
|
||||
map(two_bytes(b'-', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Pure
|
||||
}),
|
||||
map(two_bytes(b'=', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Effectful
|
||||
}),
|
||||
],
|
||||
)
|
||||
.trace("type_annotation:expression:arrow"),
|
||||
)
|
||||
.parse(arena, state.clone(), min_indent);
|
||||
|
||||
let (progress, annot, state) = match result {
|
||||
Ok((p2, (rest, space_before_arrow), state)) => {
|
||||
Ok((p2, (rest, (space_before_arrow, arrow)), state)) => {
|
||||
let (p3, return_type, state) =
|
||||
space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
@ -626,7 +634,7 @@ fn expression<'a>(
|
|||
|
||||
let result = Loc {
|
||||
region,
|
||||
value: TypeAnnotation::Function(output, arena.alloc(return_type)),
|
||||
value: TypeAnnotation::Function(output, arrow, arena.alloc(return_type)),
|
||||
};
|
||||
let progress = p1.or(p2).or(p3);
|
||||
(progress, result, state)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue