I think that PNC should land probably tomorrow - unless Joshua takes another look and has another point of contention. I have a stash with all examples and builtins migrated to use PNC(I moved the flag to an option that allow the user to choose a migration to apply (all, none, snake_case, and parens_and_commas). Should I attempt to do the Tutorial as well? Any thing else I should address as a fast follow?
The tutorial would be a good change, but a different PR would be good, yes
Oh yeah, this will all be in a separate PR for sure
I don't think there's anything that needs to be in a fast followup
Since this change will be made incrementally
But updating the builtins next would unblock deprecation of whitespace function calls
I presume you have a mental list of the steps between now and getting this into basic-(cli|webserver) releases
Happy to talk through those if you don't
But that's the main goal, after which case we do either soft deprecation via warnings or hard deprecation via removal
But I understand removal to be necessary to unblock other syntax features, so I think we should just bite that bullet
Screenshot 2025-01-01 at 9.44.43 PM.png
Hmm... not a perfect intermediate state, but it's correct, so go for it!
Here's my checklist
Sam Mohr said:
Hmm... not a perfect intermediate state, but it's correct, so go for it!
This was done by hand editing HTML in dev tools. What's off to you?
The syntax itself
Because no new lambda syntax and SD?
Not a you thing, an evolution by discrete generations
Yeah
Ah, I'd actually be very happy with this
But I really would like to do the new lambda syntax next
I mainly dislike the odd (but correct) alignment of the parens for List.map(...)
otherwise this looks good to me
Let me see how we would format this right now
That's why I was pushing for that weird Kotlin syntax that takes final argument callbacks out of the parens, but they don't seem to be popular, so :shrug:
Oh that's exactly how it will look after migration
Yep
Add a comma to the end of the lambda, and you get:
credits = List.map(
songs,
\song -> "Performed by $(song.artist)",
)
Why the double indent?
That's my fault copy/pasting
Oh, okay
To format it, I had to wrap it in a function:
does_not_matter = \songs ->
credits = List.map(
songs,
\song -> "Performed by $(song.artist)",
)
credits
I see
Because I was using a real file :-)
Could have done it as a snapshot but thought that would be silly
Since this will lead to breaking changes, I think it would be good to slip #7448 in with it. Both require updates to platforms for functionality to continue.
Also, I would advise pushing [ ] Update basic-cli / basic-webserver platforms
right after Update builtins
and definitely before the annoucement. Otherwise, people will read the announcement but not really be able to test anything cause basic-cli won't be updated yet.
This is just PNC migration - not a breaking change for the platform as long as they are using nightly compiler
Ah, this won't include the snake case renaming. I thought we were shipping both together.
Migrating builtins to snake_case _is_ breaking and a lot of work
Well, relative to migrating to PNC
One thing that I'm noticing in this migration that I'm not sure if we want is that crash, dbg, and try are looking like application instead of a keyword [space] expr sequence in a statement
I know that the plan is to deprecate try
keyword once we have PNC (is that correct @Sam Mohr ), so i'm not as worried about that, but crash and dbg I don't think should look like application even if that technically works
Yes, I believe it's better to have those keywords be visually distinct
It's a formatting issue that I'll dive into before I have to go back to work :cry:
I assumed they would also transfer to PNC.
I mean they aren't distinct in today's roc.
So why make them distinct in PNC?
They of course can be colored differently by the lsp
Yeah, it's a small but important question.
Let me check return
Also, dbg
needs to fit into method syntax pipelines.
.pass_to(dbg)
or .(dbg)()
Ok, return
does what I expect which is it is a distinct keyword in a statement
Yeah, return is a true keyword. dbg
and crash
could easily be platform functions instead as dbg!
and crash!
. that is why I don't think they should be too special
I don't think we want them marked as effectful do we?
That would color any otherwise pure function that uses them
Without syntax highlighting they aren't distinct as special.
I think he's just pointing out that they could be implemented as platform functions, not that they should have exclams
Since they're so simple
Sure
But is the intermediate state OK?
Where they are in the language still special keywords, but formatted like function application?
Oh, and I just noticed that Sam landed his PR removing backpassing
So....we'll see if I get around to dealing with all of those conflicts today
Yeah, sorry if my comment was confusing. Was just trying to say I think we should handle dbg and crash like normal functions. They really are normal platform functions. They just get a special exception not to require !
Makes sense!
That actually will simplify the compiler quite a bit
Makes me wish that return
could just be a unary op like ^
and then I don't think we would need statements at all anymore
I agree, but since return
is only used at the start of statements, it's not that bad
Yes but now it will be the only thing requiring us to having statements
Doesn't x = 123
also require that?
What I mean is now Statements can just be a enum of {BindingStmt, ExprStmt}
And technically it wouldn't be needed since an Expr block would just be something like a enum of {ExprOnly(expr), WithBindings(bindings: [Binding], expr: Expr)}
Sure, but I don't think a grammar of
(pattern "=" | "return")? expr
for statements is that bad
True
We're probably on the same page here. Would love to remove it, not sure how :shrug:
And I guess ^
would eat into the strangeness budget even though (or maybe exactly because) it's cribbed from SmallTalk :tears:
it's cribbed from SmallTalk
never would have guessed. I just thought it was something totally random.
PNC is gonna have to wait a day or two. I pulled in @Sam Mohr 's change and now there is one snapshot that is failing in a nasty way and I gotta figure out what happened.
Is there something I'd be able to help with?
Maybe
This:
C(4#
)implements e:m
C
is supposed be:
@0-22 SpaceAfter(
Defs(
Defs {
tags: [
EitherIndex(0),
],
regions: [
@0-20,
],
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: [
Ability {
header: TypeHeader {
name: @0-1 "C",
vars: [
@2-3 SpaceAfter(
NumLiteral(
"4",
),
[
LineComment(
"",
),
],
),
],
},
loc_implements: @6-16 Implements,
members: [
AbilityMember {
name: @17-18 "e",
typ: @19-20 BoundVariable(
"m",
),
},
],
},
],
value_defs: [],
},
@21-22 SpaceBefore(
Tag(
"C",
),
[
Newline,
],
),
),
[
Newline,
],
)
but comes out instead as:
@0-22 SpaceAfter(
Defs(
Defs {
tags: [
EitherIndex(2147483648),
],
regions: [
@0-20,
],
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: [],
value_defs: [
Annotation(
@0-6 Apply(
@0-6 Apply(
@0-1 Tag(
"C",
),
[
@2-3 SpaceAfter(
NumLiteral(
"4",
),
[
LineComment(
"",
),
],
),
],
ParensAndCommas,
),
[
@6-16 Identifier {
ident: "implements",
},
@17-18 Identifier {
ident: "e",
},
],
Whitespace,
),
@19-20 BoundVariable(
"m",
),
),
],
},
@21-22 SpaceBefore(
Tag(
"C",
),
[
Newline,
],
),
),
[
Newline,
],
)
When you say "is supposed to be", do you mean that's the old state, or do you mean that's what you personally think it should be?
I think it's meant to be a Ability, but this "expr", even formatted makes zero sense to me at all
I didn't think you could have implements
in the header of an annotation
I think this test isn't super useful
Here's what it supposedly is formatted:
C 4 #
implements e : m
C
Okay, that makes more sense, now that I've referenced the ability docs
No, I think that your new behavior is correct
The closest logical thing would be:
C a #
implements e : m
C
Really?
Oh, actually
So we're supposed to have two parsing formats
Because if you remove the comment/newline you get
C a implements e : m
C
Types have their args applied with spaces
But values have them applied with parens
Yes
So your code is parsing it like a value instead of a type
And that will remain the case after PNC
Oh, so it's the order that we look for defs then right?
That might be it
I'm looking now
It seems like if we find the a Expr::Var("implements") or Pattern:Identifier("implements") we should Err out with a malformed...
I'm not sure I agree, but maybe
There is logic to say any ident that matches a keyword is blocked
But we don't include IMPLEMENTS
in KEYWORDS
I'd add that keyword and see if it breaks
Or rather, that this parses correctly
Ok, I'll try the same
But this I think is because we only parse an ability if the first expression in the expression chain is a tag
Now with parens, it will always be an Apply
Man, I'm flip-flopping over here
So this is similar to how we have to accept that SomeTag(1,2)
is equivalent to SomeTag 1 2
and never SomeTag (1,2)
I think this case is testing a behavior that makes sense if PNC doesn't exist, but makes less sense in PNC land. Maybe this is crazy, but I think you should just delete this
I'm OK with it if you are. I'll make sure that
C 4 #
implements e : m
C
Give the right AST
Yeah it does - with a little swapping around of Spaces
I can rename it to not mention parens and just overwrite
Rebase complete
Now here's hoping I can get an approval before someone lands something else in the parser/formatter :fingers_crossed:
Looking now
Shoot, I have a can test failure
Looks like a couple were updated by you Sam, I just gotta add the PatternAppyStyle
Okay, still reviewing
Done
I love insta
It makes life much easier and brainless
Can we move test_syntax to this please?
If you make a PR, I'll approve it
I can try sometime soon
I have like 3 other issues queued up :-)
Luckily Joshua went over this pretty good, so the review should be relatively easy
This PR is now only blocked by a failed panic check. I added a new .unwrap()
in the minimize binary in test_syntax during arg parsing. I believe that is reasonable behavior (and following the local pattern). If someone with authority to override it could take a look I would be very thankful.
I replied in the PR
Just tagged you in a comment on the line
I replaced
let text = std::fs::read_to_string(&args[index + 1]).unwrap();
with
let text = if input == "-" {
std::io::stdin().read_to_string(&mut buf).unwrap();
buf.to_string()
} else {
std::fs::read_to_string(input).unwrap()
};
I'm going to write a Roc program that can actually show you the panics and unwraps added in a feature branch
Actually you really just need to change the violations collection line to:
VIOLATIONS="$(cargo clippy --no-deps -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic 2> >(grep -C 1 -e "warning: \`panic\`" -e "warning: used" -e "warning: usage of" | grep -e " --> " | sed "s/ *--> *//g"))"
Then compare the number of violations
NUM_SOURCE_VIOLATIONS="$(echo "$SOURCE_VIOLATIONS" | wc -l)"
NUM_TARGET_VIOLATIONS="$(echo "$TARGET_VIOLATIONS" | wc -l)"
if [ "$SOURCE_VIOLATIONS" -gt "$TARGET_VIOLATIONS" ]; then
...
echo "Here are new warnings I found in the target branch:"
comm -13 source_branch_dir/violations target_branch_dir/violations
fi
That may lead to false positives from moved files (like during a refactor) but that could be an acceptable shortcoming
It would at least narrow down your search
And we could make the language have more hedging :smile:
echo "Here are some location that **may** have introduced new violations in the target branch:"
I wanted to do something much more ambitious with Roc, like using histogram diff and parsing the patch to find actual net new lines of code. But this is a step forward I think
Agreed :)
I'll do this when I'm done with the rebase I'm working on - which will be after work today :-)
Last updated: Jul 06 2025 at 12:14 UTC