mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-01 05:24:15 +00:00
Parsing support for snake_case identifiers
In this initial commit, I have done the following: - Added unit tests to roc_parse's ident.rs file to cover at least the simplest Ident enum cases (Tag, OpaqueRef, and simple Access) - Added '_' as a valid "rest" character in both uppercase and lowercase identifier parts - Updated the test_syntax snapshots appropriately There is still a lot left to do here. Such as: - Do we want to allow multiple '_'s to parse successfully? - Handle qualified access - Handle accessor functions - Handle record update functions - Remove the UnderscoreInMiddle case from BadIdent - Write unit tests for Malformed Idents I am not a "Rustacean" by any means, but have been through the Book in years past. Any feedback on the way I wrote the tests or any other part of the implementation would be very appreciated.
This commit is contained in:
parent
d7825428df
commit
a2083cec30
31 changed files with 1214 additions and 460 deletions
|
|
@ -1,5 +1,5 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_fmt::{annotation::Formattable, header::fmt_header};
|
||||
use roc_fmt::{annotation::Formattable, annotation::MigrationFlags, header::fmt_header};
|
||||
use roc_parse::{
|
||||
ast::{Defs, Expr, FullAst, Header, Malformed, SpacesBefore},
|
||||
header::parse_module_defs,
|
||||
|
|
@ -83,24 +83,25 @@ impl<'a> Output<'a> {
|
|||
pub fn format(&self) -> InputOwned {
|
||||
let arena = Bump::new();
|
||||
let mut buf = Buf::new_in(&arena);
|
||||
let flags = MigrationFlags::new(false);
|
||||
match self {
|
||||
Output::Header(header) => {
|
||||
fmt_header(&mut buf, header);
|
||||
fmt_header(&mut buf, header, &flags);
|
||||
buf.fmt_end_of_file();
|
||||
InputOwned::Header(buf.as_str().to_string())
|
||||
}
|
||||
Output::ModuleDefs(defs) => {
|
||||
defs.format(&mut buf, 0);
|
||||
defs.format(&mut buf, &flags, 0);
|
||||
buf.fmt_end_of_file();
|
||||
InputOwned::ModuleDefs(buf.as_str().to_string())
|
||||
}
|
||||
Output::Expr(expr) => {
|
||||
expr.format(&mut buf, 0);
|
||||
expr.format(&mut buf, &flags, 0);
|
||||
InputOwned::Expr(buf.as_str().to_string())
|
||||
}
|
||||
Output::Full(full) => {
|
||||
fmt_header(&mut buf, &full.header);
|
||||
full.defs.format(&mut buf, 0);
|
||||
fmt_header(&mut buf, &full.header, &flags);
|
||||
full.defs.format(&mut buf, &flags, 0);
|
||||
buf.fmt_end_of_file();
|
||||
InputOwned::Full(buf.as_str().to_string())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
Closure(
|
||||
[
|
||||
@1-11 MalformedIdent(
|
||||
"the_answer",
|
||||
UnderscoreInMiddle(
|
||||
@5,
|
||||
),
|
||||
),
|
||||
],
|
||||
@15-17 Num(
|
||||
"42",
|
||||
),
|
||||
)
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-3,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "J",
|
||||
vars: [],
|
||||
},
|
||||
ann: @2-3 Apply(
|
||||
"",
|
||||
"R",
|
||||
[],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@5-8 SpaceBefore(
|
||||
MalformedIdent(
|
||||
"n_p",
|
||||
UnderscoreInMiddle(
|
||||
@7,
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
SpaceAfter(
|
||||
Closure(
|
||||
[
|
||||
@1-11 Identifier {
|
||||
ident: "the_answer",
|
||||
},
|
||||
],
|
||||
@15-17 Num(
|
||||
"42",
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
||||
|
|
@ -0,0 +1 @@
|
|||
\the_answer -> 42
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-3,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "J",
|
||||
vars: [],
|
||||
},
|
||||
ann: @2-3 Apply(
|
||||
"",
|
||||
"R",
|
||||
[],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@4-7 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "n_p",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
J:R
|
||||
n_p
|
||||
n_p
|
||||
|
|
@ -4,6 +4,7 @@ extern crate indoc;
|
|||
#[cfg(test)]
|
||||
mod test_fmt {
|
||||
use bumpalo::Bump;
|
||||
use roc_fmt::annotation::MigrationFlags;
|
||||
use roc_fmt::def::fmt_defs;
|
||||
use roc_fmt::header::fmt_header;
|
||||
use roc_fmt::Buf;
|
||||
|
|
@ -36,11 +37,12 @@ mod test_fmt {
|
|||
state: State<'a>,
|
||||
buf: &mut Buf<'_>,
|
||||
) {
|
||||
fmt_header(buf, header);
|
||||
let flags = MigrationFlags::new(false);
|
||||
fmt_header(buf, header, &flags);
|
||||
|
||||
match parse_module_defs(arena, state, Defs::default()) {
|
||||
Ok(loc_defs) => {
|
||||
fmt_defs(buf, &loc_defs, 0);
|
||||
fmt_defs(buf, &loc_defs, &flags, 0);
|
||||
}
|
||||
Err(error) => {
|
||||
let src = if src.len() > 1000 {
|
||||
|
|
@ -1492,7 +1494,7 @@ mod test_fmt {
|
|||
fn parenthetical_def() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
(UserId userId) = 5
|
||||
(UserId user_id) = 5
|
||||
y = 10
|
||||
|
||||
42
|
||||
|
|
@ -1502,7 +1504,7 @@ mod test_fmt {
|
|||
expr_formats_same(indoc!(
|
||||
r"
|
||||
# A
|
||||
(UserId userId) = 5
|
||||
(UserId user_id) = 5
|
||||
# B
|
||||
y = 10
|
||||
|
||||
|
|
@ -1539,13 +1541,13 @@ mod test_fmt {
|
|||
fn lambda_returns_record() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toRecord = \_ -> {
|
||||
to_record = \_ -> {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
));
|
||||
|
||||
|
|
@ -1560,7 +1562,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toRecord = \_ ->
|
||||
to_record = \_ ->
|
||||
val = 0
|
||||
|
||||
{
|
||||
|
|
@ -1569,32 +1571,32 @@ mod test_fmt {
|
|||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r"
|
||||
toRecord = \_ ->
|
||||
to_record = \_ ->
|
||||
{
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r"
|
||||
toRecord = \_ -> {
|
||||
to_record = \_ -> {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
),
|
||||
);
|
||||
|
|
@ -1604,13 +1606,13 @@ mod test_fmt {
|
|||
fn lambda_returns_list() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toList = \_ -> [
|
||||
to_list = \_ -> [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
));
|
||||
|
||||
|
|
@ -1625,7 +1627,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toList = \_ ->
|
||||
to_list = \_ ->
|
||||
val = 0
|
||||
|
||||
[
|
||||
|
|
@ -1634,32 +1636,32 @@ mod test_fmt {
|
|||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r"
|
||||
toList = \_ ->
|
||||
to_list = \_ ->
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r"
|
||||
toList = \_ -> [
|
||||
to_list = \_ -> [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
),
|
||||
);
|
||||
|
|
@ -3116,7 +3118,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
myDef =
|
||||
my_def =
|
||||
list = [
|
||||
a,
|
||||
b,
|
||||
|
|
@ -3127,7 +3129,7 @@ mod test_fmt {
|
|||
d,
|
||||
}
|
||||
|
||||
myDef
|
||||
my_def
|
||||
"
|
||||
));
|
||||
|
||||
|
|
@ -3672,7 +3674,7 @@ mod test_fmt {
|
|||
fn def_when() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
myLongFunctionName = \x ->
|
||||
my_long_function_name = \x ->
|
||||
when b is
|
||||
1 | 2 ->
|
||||
when c is
|
||||
|
|
@ -4974,10 +4976,10 @@ mod test_fmt {
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [ mainForHost ]
|
||||
provides [ main_for_host ]
|
||||
|
||||
mainForHost : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
mainForHost = main
|
||||
main_for_host : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
main_for_host = main
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
|
|
@ -4987,10 +4989,10 @@ mod test_fmt {
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host]
|
||||
|
||||
mainForHost : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
mainForHost = main
|
||||
main_for_host : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
main_for_host = main
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
|
@ -5313,8 +5315,8 @@ mod test_fmt {
|
|||
fn backpassing_simple() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
getChar = \ctx ->
|
||||
x <- Task.await (getCharScope scope)
|
||||
get_char = \ctx ->
|
||||
x <- Task.await (get_char_scope scope)
|
||||
42
|
||||
|
||||
42
|
||||
|
|
@ -5326,8 +5328,8 @@ mod test_fmt {
|
|||
fn backpassing_apply_tag() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
getChar = \ctx ->
|
||||
(T val newScope) <- Task.await (getCharScope scope)
|
||||
get_char = \ctx ->
|
||||
(T val new_scope) <- Task.await (get_char_scope scope)
|
||||
42
|
||||
|
||||
42
|
||||
|
|
@ -5406,9 +5408,9 @@ mod test_fmt {
|
|||
fn backpassing_body_on_newline() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
getChar = \ctx ->
|
||||
get_char = \ctx ->
|
||||
x <-
|
||||
Task.await (getCharScope scope)
|
||||
Task.await (get_char_scope scope)
|
||||
42
|
||||
|
||||
42
|
||||
|
|
|
|||
|
|
@ -265,12 +265,10 @@ mod test_snapshots {
|
|||
fail/where_type_variable.expr,
|
||||
fail/wild_case_arrow.expr,
|
||||
malformed/bad_opaque_ref.expr,
|
||||
malformed/malformed_ident_due_to_underscore.expr,
|
||||
malformed/malformed_pattern_field_access.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
malformed/malformed_pattern_module_name.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
malformed/module_dot_tuple.expr,
|
||||
malformed/qualified_tag.expr,
|
||||
malformed/underscore_expr_in_def.expr,
|
||||
pass/ability_demand_signature_is_multiline.expr,
|
||||
pass/ability_multi_line.expr,
|
||||
pass/ability_single_line.expr,
|
||||
|
|
@ -575,6 +573,7 @@ mod test_snapshots {
|
|||
pass/return_with_after.expr,
|
||||
pass/separate_defs.moduledefs,
|
||||
pass/single_arg_closure.expr,
|
||||
pass/single_arg_with_underscore_closure.expr,
|
||||
pass/single_underscore_closure.expr,
|
||||
pass/space_before_colon.full,
|
||||
pass/space_before_parens_space_after.expr,
|
||||
|
|
@ -627,6 +626,7 @@ mod test_snapshots {
|
|||
pass/unary_not.expr,
|
||||
pass/unary_not_with_parens.expr,
|
||||
pass/underscore_backpassing.expr,
|
||||
pass/underscore_expr_in_def.expr,
|
||||
pass/underscore_in_assignment_pattern.expr,
|
||||
pass/value_def_confusion.expr,
|
||||
pass/var_else.expr,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue