mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-01 13:34:15 +00:00
Merge remote-tracking branch 'remote/main' into rebuild-platform
This commit is contained in:
commit
c00db6da37
100 changed files with 2554 additions and 279 deletions
|
|
@ -496,6 +496,9 @@ pub enum Expr<'a> {
|
|||
// This form of debug is a desugared call to roc_dbg
|
||||
LowLevelDbg(&'a (&'a str, &'a str), &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
/// The `try` keyword that performs early return on errors
|
||||
Try,
|
||||
|
||||
// Application
|
||||
/// To apply by name, do Apply(Var(...), ...)
|
||||
/// To apply a tag by name, do Apply(Tag(...), ...)
|
||||
|
|
@ -520,6 +523,13 @@ pub enum Expr<'a> {
|
|||
&'a [&'a WhenBranch<'a>],
|
||||
),
|
||||
|
||||
Return(
|
||||
/// The return value
|
||||
&'a Loc<Expr<'a>>,
|
||||
/// The unused code after the return statement
|
||||
Option<&'a Loc<Expr<'a>>>,
|
||||
),
|
||||
|
||||
// Blank Space (e.g. comments, spaces, newlines) before or after an expression.
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a Expr<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
|
@ -665,10 +675,14 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
Expr::Dbg => false,
|
||||
Expr::DbgStmt(a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::LowLevelDbg(_, a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::Try => false,
|
||||
Expr::UnaryOp(a, _) => is_expr_suffixed(&a.value),
|
||||
Expr::When(cond, branches) => {
|
||||
is_expr_suffixed(&cond.value) || branches.iter().any(|x| is_when_branch_suffixed(x))
|
||||
}
|
||||
Expr::Return(a, b) => {
|
||||
is_expr_suffixed(&a.value) || b.is_some_and(|loc_b| is_expr_suffixed(&loc_b.value))
|
||||
}
|
||||
Expr::SpaceBefore(a, _) => is_expr_suffixed(a),
|
||||
Expr::SpaceAfter(a, _) => is_expr_suffixed(a),
|
||||
Expr::MalformedIdent(_, _) => false,
|
||||
|
|
@ -938,6 +952,15 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
}
|
||||
Return(return_value, after_return) => {
|
||||
if let Some(after_return) = after_return {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&return_value.value);
|
||||
expr_stack.push(&after_return.value);
|
||||
} else {
|
||||
expr_stack.push(&return_value.value);
|
||||
}
|
||||
}
|
||||
Apply(fun, args, _) => {
|
||||
expr_stack.reserve(args.len() + 1);
|
||||
expr_stack.push(&fun.value);
|
||||
|
|
@ -1008,6 +1031,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
| Underscore(_)
|
||||
| Crash
|
||||
| Dbg
|
||||
| Try
|
||||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| MalformedIdent(_, _)
|
||||
|
|
@ -2464,6 +2488,8 @@ impl<'a> Malformed for Expr<'a> {
|
|||
Dbg => false,
|
||||
DbgStmt(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
LowLevelDbg(_, condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Try => false,
|
||||
Return(return_value, after_return) => return_value.is_malformed() || after_return.is_some_and(|ar| ar.is_malformed()),
|
||||
Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()),
|
||||
BinOps(firsts, last) => firsts.iter().any(|(expr, _)| expr.is_malformed()) || last.is_malformed(),
|
||||
UnaryOp(expr, _) => expr.is_malformed(),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::parser::{
|
|||
map_with_arena, optional, reset_min_indent, sep_by1, sep_by1_e, set_min_indent, skip_first,
|
||||
skip_second, specialize_err, specialize_err_ref, then, two_bytes, zero_or_more, EClosure,
|
||||
EExpect, EExpr, EIf, EImport, EImportParams, EInParens, EList, ENumber, EPattern, ERecord,
|
||||
EString, EType, EWhen, Either, ParseResult, Parser, SpaceProblem,
|
||||
EReturn, EString, EType, EWhen, Either, ParseResult, Parser, SpaceProblem,
|
||||
};
|
||||
use crate::pattern::closure_param;
|
||||
use crate::state::State;
|
||||
|
|
@ -195,6 +195,7 @@ fn loc_term_or_underscore_or_conditional<'a>(
|
|||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(crash_kw()),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(try_kw()),
|
||||
loc(underscore_expression()),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
|
|
@ -217,6 +218,7 @@ fn loc_term_or_underscore<'a>(
|
|||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(try_kw()),
|
||||
loc(underscore_expression()),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
|
|
@ -235,6 +237,7 @@ fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EEx
|
|||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(try_kw()),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
ident_seq(),
|
||||
|
|
@ -546,6 +549,7 @@ fn stmt_start<'a>(
|
|||
EExpr::Dbg,
|
||||
dbg_stmt_help(options, preceding_comment)
|
||||
)),
|
||||
loc(specialize_err(EExpr::Return, return_help(options))),
|
||||
loc(specialize_err(EExpr::Import, map(import(), Stmt::ValueDef))),
|
||||
map(
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
|
|
@ -1443,6 +1447,7 @@ fn parse_stmt_operator<'a>(
|
|||
let op_start = loc_op.region.start();
|
||||
let op_end = loc_op.region.end();
|
||||
let new_start = state.pos();
|
||||
|
||||
match op {
|
||||
OperatorOrDef::BinOp(BinOp::Minus) if expr_state.end != op_start && op_end == new_start => {
|
||||
parse_negated_term(
|
||||
|
|
@ -2127,6 +2132,8 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
pattern
|
||||
}
|
||||
|
||||
Expr::Try => Pattern::Identifier { ident: "try" },
|
||||
|
||||
Expr::SpaceBefore(..) | Expr::SpaceAfter(..) | Expr::ParensAround(..) => unreachable!(),
|
||||
|
||||
Expr::Record(fields) => {
|
||||
|
|
@ -2172,6 +2179,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::Dbg
|
||||
| Expr::DbgStmt(_, _)
|
||||
| Expr::LowLevelDbg(_, _, _)
|
||||
| Expr::Return(_, _)
|
||||
| Expr::MalformedClosure
|
||||
| Expr::MalformedSuffixed(..)
|
||||
| Expr::PrecedenceConflict { .. }
|
||||
|
|
@ -2644,6 +2652,33 @@ fn expect_help<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn return_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Stmt<'a>, EReturn<'a>> {
|
||||
(move |arena: &'a Bump, state: State<'a>, min_indent| {
|
||||
let (_, return_kw, state) = loc(parser::keyword(keyword::RETURN, EReturn::Return))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, return_value, state) = parse_block(
|
||||
options,
|
||||
arena,
|
||||
state,
|
||||
true,
|
||||
EReturn::IndentReturnValue,
|
||||
EReturn::ReturnValue,
|
||||
)
|
||||
.map_err(|(_, f)| (MadeProgress, f))?;
|
||||
|
||||
let region = Region::span_across(&return_kw.region, &return_value.region);
|
||||
|
||||
let stmt = Stmt::Expr(Expr::Return(
|
||||
arena.alloc(Loc::at(region, return_value.value)),
|
||||
None,
|
||||
));
|
||||
|
||||
Ok((MadeProgress, stmt, state))
|
||||
})
|
||||
.trace("return_help")
|
||||
}
|
||||
|
||||
fn dbg_stmt_help<'a>(
|
||||
options: ExprParseOptions,
|
||||
preceding_comment: Region,
|
||||
|
|
@ -2682,6 +2717,16 @@ fn dbg_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpect<'a>> {
|
|||
.trace("dbg_kw")
|
||||
}
|
||||
|
||||
fn try_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
(move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let (_, _, next_state) =
|
||||
parser::keyword("try", EExpr::Try).parse(arena, state, min_indent)?;
|
||||
|
||||
Ok((MadeProgress, Expr::Try, next_state))
|
||||
})
|
||||
.trace("try_kw")
|
||||
}
|
||||
|
||||
fn import<'a>() -> impl Parser<'a, ValueDef<'a>, EImport<'a>> {
|
||||
skip_second(
|
||||
skip_first(
|
||||
|
|
@ -3060,6 +3105,20 @@ fn stmts_to_defs<'a>(
|
|||
while i < stmts.len() {
|
||||
let sp_stmt = stmts[i];
|
||||
match sp_stmt.item.value {
|
||||
Stmt::Expr(Expr::Return(return_value, _after_return)) => {
|
||||
if i == stmts.len() - 1 {
|
||||
last_expr = Some(Loc::at_zero(Expr::Return(return_value, None)));
|
||||
} else {
|
||||
let rest = stmts_to_expr(&stmts[i + 1..], arena)?;
|
||||
last_expr = Some(Loc::at_zero(Expr::Return(
|
||||
return_value,
|
||||
Some(arena.alloc(rest)),
|
||||
)));
|
||||
}
|
||||
|
||||
// don't re-process the rest of the statements, they got consumed by the early return
|
||||
break;
|
||||
}
|
||||
Stmt::Expr(e) => {
|
||||
if is_expr_suffixed(&e) && i + 1 < stmts.len() {
|
||||
defs.push_value_def(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ pub const DBG: &str = "dbg";
|
|||
pub const IMPORT: &str = "import";
|
||||
pub const EXPECT: &str = "expect";
|
||||
pub const EXPECT_FX: &str = "expect-fx";
|
||||
pub const RETURN: &str = "return";
|
||||
pub const CRASH: &str = "crash";
|
||||
|
||||
// These keywords are valid in imports
|
||||
|
|
@ -21,6 +22,6 @@ pub const WHERE: &str = "where";
|
|||
// These keywords are valid in headers
|
||||
pub const PLATFORM: &str = "platform";
|
||||
|
||||
pub const KEYWORDS: [&str; 11] = [
|
||||
IF, THEN, ELSE, WHEN, AS, IS, DBG, IMPORT, EXPECT, EXPECT_FX, CRASH,
|
||||
pub const KEYWORDS: [&str; 12] = [
|
||||
IF, THEN, ELSE, WHEN, AS, IS, DBG, IMPORT, EXPECT, EXPECT_FX, RETURN, CRASH,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ pub mod keyword;
|
|||
pub mod normalize;
|
||||
pub mod number_literal;
|
||||
pub mod pattern;
|
||||
pub mod problems;
|
||||
pub mod src64;
|
||||
pub mod state;
|
||||
pub mod string_literal;
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ use crate::{
|
|||
parser::{
|
||||
EAbility, EClosure, EExpect, EExposes, EExpr, EHeader, EIf, EImport, EImportParams,
|
||||
EImports, EInParens, EList, EPackageEntry, EPackageName, EPackages, EParams, EPattern,
|
||||
EProvides, ERecord, ERequires, EString, EType, ETypeAbilityImpl, ETypeApply, ETypeInParens,
|
||||
ETypeInlineAlias, ETypeRecord, ETypeTagUnion, ETypedIdent, EWhen, PInParens, PList,
|
||||
PRecord, SyntaxError,
|
||||
EProvides, ERecord, ERequires, EReturn, EString, EType, ETypeAbilityImpl, ETypeApply,
|
||||
ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, ETypedIdent, EWhen, PInParens,
|
||||
PList, PRecord, SyntaxError,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -756,6 +756,11 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
Expr::Try => Expr::Try,
|
||||
Expr::Return(a, b) => Expr::Return(
|
||||
arena.alloc(a.normalize(arena)),
|
||||
b.map(|loc_b| &*arena.alloc(loc_b.normalize(arena))),
|
||||
),
|
||||
Expr::Apply(a, b, c) => {
|
||||
Expr::Apply(arena.alloc(a.normalize(arena)), b.normalize(arena), c)
|
||||
}
|
||||
|
|
@ -1038,6 +1043,9 @@ impl<'a> Normalize<'a> for EExpr<'a> {
|
|||
EExpr::Expect(inner_err, _pos) => {
|
||||
EExpr::Expect(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
EExpr::Return(inner_err, _pos) => {
|
||||
EExpr::Return(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
EExpr::Dbg(inner_err, _pos) => EExpr::Dbg(inner_err.normalize(arena), Position::zero()),
|
||||
EExpr::Import(inner_err, _pos) => {
|
||||
EExpr::Import(inner_err.normalize(arena), Position::zero())
|
||||
|
|
@ -1047,6 +1055,7 @@ impl<'a> Normalize<'a> for EExpr<'a> {
|
|||
}
|
||||
EExpr::Underscore(_pos) => EExpr::Underscore(Position::zero()),
|
||||
EExpr::Crash(_pos) => EExpr::Crash(Position::zero()),
|
||||
EExpr::Try(_pos) => EExpr::Try(Position::zero()),
|
||||
EExpr::InParens(inner_err, _pos) => {
|
||||
EExpr::InParens(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
|
|
@ -1472,6 +1481,20 @@ impl<'a> Normalize<'a> for EExpect<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Normalize<'a> for EReturn<'a> {
|
||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
||||
match self {
|
||||
EReturn::Space(inner_err, _) => EReturn::Space(*inner_err, Position::zero()),
|
||||
EReturn::Return(_) => EReturn::Return(Position::zero()),
|
||||
EReturn::ReturnValue(inner_err, _) => {
|
||||
EReturn::ReturnValue(arena.alloc(inner_err.normalize(arena)), Position::zero())
|
||||
}
|
||||
EReturn::IndentReturnValue(_) => EReturn::IndentReturnValue(Position::zero()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Normalize<'a> for EIf<'a> {
|
||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ impl_space_problem! {
|
|||
EPattern<'a>,
|
||||
EProvides<'a>,
|
||||
ERecord<'a>,
|
||||
EReturn<'a>,
|
||||
ERequires<'a>,
|
||||
EString<'a>,
|
||||
EType<'a>,
|
||||
|
|
@ -337,10 +338,12 @@ pub enum EExpr<'a> {
|
|||
Expect(EExpect<'a>, Position),
|
||||
Dbg(EExpect<'a>, Position),
|
||||
Import(EImport<'a>, Position),
|
||||
Return(EReturn<'a>, Position),
|
||||
|
||||
Closure(EClosure<'a>, Position),
|
||||
Underscore(Position),
|
||||
Crash(Position),
|
||||
Try(Position),
|
||||
|
||||
InParens(EInParens<'a>, Position),
|
||||
Record(ERecord<'a>, Position),
|
||||
|
|
@ -513,6 +516,14 @@ pub enum EExpect<'a> {
|
|||
IndentCondition(Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EReturn<'a> {
|
||||
Space(BadInputError, Position),
|
||||
Return(Position),
|
||||
ReturnValue(&'a EExpr<'a>, Position),
|
||||
IndentReturnValue(Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EImport<'a> {
|
||||
Import(Position),
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
use roc_region::all::Loc;
|
||||
|
||||
pub type Problems = Vec<Loc<Problem>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Problem {
|
||||
// UNICODE CODE POINT
|
||||
/// TODO Invalid hex code - Unicode code points must be specified using hexadecimal characters (the numbers 0-9 and letters A-F)
|
||||
NonHexCharsInUnicodeCodePt,
|
||||
/// TODO Invalid Unicode code point. It must be no more than \\u{10FFFF}.
|
||||
UnicodeCodePtTooLarge,
|
||||
InvalidUnicodeCodePt,
|
||||
MalformedEscapedUnicode,
|
||||
NoUnicodeDigits,
|
||||
|
||||
// STRING LITERAL
|
||||
NewlineInLiteral,
|
||||
Tab,
|
||||
CarriageReturn,
|
||||
NullChar,
|
||||
UnsupportedEscapedChar,
|
||||
|
||||
// NUMBER LITERAL
|
||||
OutsideSupportedRange,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue