mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Parse inline imports and ingested files at the expression level
``` numbers = import "numbers.json" as numbersJson : Str import json.Decode exposing [decode, list, int] numbersJson |> decode (list int) |> Result.withDefault [] ```
This commit is contained in:
parent
2d93f0c3f1
commit
11e0202eb9
8 changed files with 219 additions and 5 deletions
|
@ -306,6 +306,7 @@ fn expr_start<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, E
|
|||
loc!(specialize(EExpr::When, when::expr_help(options))),
|
||||
loc!(specialize(EExpr::Expect, expect_help(options))),
|
||||
loc!(specialize(EExpr::Dbg, dbg_help(options))),
|
||||
loc!(import_help(options)),
|
||||
loc!(specialize(EExpr::Closure, closure_help(options))),
|
||||
loc!(expr_operator_chain(options)),
|
||||
fail_expr_start_e()
|
||||
|
@ -2181,7 +2182,7 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo
|
|||
// closure_help_help(options)
|
||||
map_with_arena!(
|
||||
// After the first token, all other tokens must be indented past the start of the line
|
||||
indented_seq!(
|
||||
indented_seq_skip_first!(
|
||||
// All closures start with a '\' - e.g. (\x -> x + 1)
|
||||
word1_indent(b'\\', EClosure::Start),
|
||||
// Once we see the '\', we're committed to parsing this as a closure.
|
||||
|
@ -2225,7 +2226,7 @@ mod when {
|
|||
pub fn expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EWhen<'a>> {
|
||||
map_with_arena!(
|
||||
and!(
|
||||
indented_seq!(
|
||||
indented_seq_skip_first!(
|
||||
parser::keyword_e(keyword::WHEN, EWhen::When),
|
||||
space0_around_e_no_after_indent_check(
|
||||
specialize_ref(EWhen::Condition, expr_start(options)),
|
||||
|
@ -2236,7 +2237,7 @@ mod when {
|
|||
// ambiguity. The formatter will fix it up.
|
||||
//
|
||||
// We require that branches are indented relative to the line containing the `is`.
|
||||
indented_seq!(
|
||||
indented_seq_skip_first!(
|
||||
parser::keyword_e(keyword::IS, EWhen::Is),
|
||||
branches(options)
|
||||
)
|
||||
|
@ -2528,6 +2529,18 @@ fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<
|
|||
}
|
||||
}
|
||||
|
||||
fn import_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let (_, import_def, state) =
|
||||
loc!(specialize(EExpr::Import, import())).parse(arena, state, min_indent)?;
|
||||
|
||||
let mut defs = Defs::default();
|
||||
defs.push_value_def(import_def.value, import_def.region, &[], &[]);
|
||||
|
||||
parse_defs_expr(options, min_indent, defs, arena, state)
|
||||
}
|
||||
}
|
||||
|
||||
fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<'a>> {
|
||||
move |arena: &'a Bump, state, min_indent| {
|
||||
let (_, _, state) =
|
||||
|
|
|
@ -1384,7 +1384,7 @@ macro_rules! record {
|
|||
/// Similar to `and`, but we modify the min_indent of the second parser to be
|
||||
/// 1 greater than the line_indent() at the start of the first parser.
|
||||
#[macro_export]
|
||||
macro_rules! indented_seq {
|
||||
macro_rules! indented_seq_skip_first {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, _min_indent: u32| {
|
||||
let start_indent = state.line_indent();
|
||||
|
@ -1409,6 +1409,34 @@ macro_rules! indented_seq {
|
|||
};
|
||||
}
|
||||
|
||||
/// Similar to `and`, but we modify the min_indent of the second parser to be
|
||||
/// 1 greater than the line_indent() at the start of the first parser.
|
||||
#[macro_export]
|
||||
macro_rules! indented_seq {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, _min_indent: u32| {
|
||||
let start_indent = state.line_indent();
|
||||
|
||||
// TODO: we should account for min_indent here, but this doesn't currently work
|
||||
// because min_indent is sometimes larger than it really should be, which is in turn
|
||||
// due to uses of `increment_indent`.
|
||||
//
|
||||
// let p1_indent = std::cmp::max(start_indent, min_indent);
|
||||
|
||||
let p1_indent = start_indent;
|
||||
let p2_indent = p1_indent + 1;
|
||||
|
||||
match $p1.parse(arena, state, p1_indent) {
|
||||
Ok((p1, out1, state)) => match $p2.parse(arena, state, p2_indent) {
|
||||
Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)),
|
||||
Err((p2, fail)) => Err((p1.or(p2), fail)),
|
||||
},
|
||||
Err((progress, fail)) => Err((progress, fail)),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Similar to `and`, but we modify the min_indent of the second parser to be
|
||||
/// 1 greater than the column() at the start of the first parser.
|
||||
#[macro_export]
|
||||
|
|
|
@ -386,7 +386,7 @@ fn record_type<'a>(
|
|||
|
||||
fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||
map!(
|
||||
and!(
|
||||
indented_seq!(
|
||||
specialize(EType::TApply, concrete_type()),
|
||||
// Optionally parse space-separated arguments for the constructor,
|
||||
// e.g. `Str Float` in `Map Str Float`
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
Index(2147483649),
|
||||
],
|
||||
regions: [
|
||||
@0-26,
|
||||
@27-50,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 0, length = 1),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 1, length = 0),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
ModuleImport(
|
||||
ModuleImport {
|
||||
before_name: [],
|
||||
name: @7-11 ImportedModuleName {
|
||||
package: None,
|
||||
name: "Json",
|
||||
},
|
||||
alias: None,
|
||||
exposed: Some(
|
||||
KeywordItem {
|
||||
keyword: Spaces {
|
||||
before: [],
|
||||
item: ImportExposingKeyword,
|
||||
after: [],
|
||||
},
|
||||
item: [
|
||||
@22-25 ExposedName(
|
||||
"int",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
ModuleImport(
|
||||
ModuleImport {
|
||||
before_name: [],
|
||||
name: @34-44 ImportedModuleName {
|
||||
package: None,
|
||||
name: "JsonEncode",
|
||||
},
|
||||
alias: Some(
|
||||
KeywordItem {
|
||||
keyword: Spaces {
|
||||
before: [],
|
||||
item: ImportAsKeyword,
|
||||
after: [],
|
||||
},
|
||||
item: @48-50 ImportAlias(
|
||||
"JE",
|
||||
),
|
||||
},
|
||||
),
|
||||
exposed: None,
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@52-70 SpaceBefore(
|
||||
Apply(
|
||||
@52-61 Var {
|
||||
module_name: "JE",
|
||||
ident: "encode",
|
||||
},
|
||||
[
|
||||
@63-69 ParensAround(
|
||||
Apply(
|
||||
@63-66 Var {
|
||||
module_name: "",
|
||||
ident: "int",
|
||||
},
|
||||
[
|
||||
@67-69 Num(
|
||||
"42",
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -0,0 +1,4 @@
|
|||
import Json exposing [int]
|
||||
import JsonEncode as JE
|
||||
|
||||
JE.encode (int 42)
|
|
@ -0,0 +1,63 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-33,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
IngestedFileImport(
|
||||
IngestedFileImport {
|
||||
before_path: [],
|
||||
path: @7-19 PlainLine(
|
||||
"users.json",
|
||||
),
|
||||
name: KeywordItem {
|
||||
keyword: Spaces {
|
||||
before: [],
|
||||
item: ImportAsKeyword,
|
||||
after: [],
|
||||
},
|
||||
item: @23-33 TypedIdent {
|
||||
ident: @23-27 "data",
|
||||
spaces_before_colon: [],
|
||||
ann: @30-33 Apply(
|
||||
"",
|
||||
"Str",
|
||||
[],
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@35-49 SpaceBefore(
|
||||
Apply(
|
||||
@35-44 Var {
|
||||
module_name: "",
|
||||
ident: "parseJson",
|
||||
},
|
||||
[
|
||||
@45-49 Var {
|
||||
module_name: "",
|
||||
ident: "data",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
import "users.json" as data : Str
|
||||
|
||||
parseJson data
|
|
@ -330,6 +330,8 @@ mod test_snapshots {
|
|||
pass/import_with_comments.moduledefs,
|
||||
pass/import_with_exposed.moduledefs,
|
||||
pass/ingested_file.moduledefs,
|
||||
pass/inline_import.expr,
|
||||
pass/inline_ingested_file.expr,
|
||||
pass/int_with_underscore.expr,
|
||||
pass/interface_with_newline.header,
|
||||
pass/lambda_in_chain.expr,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue