Skip to content

Conversation

cometkim
Copy link
Member

We need to settle on #7172 before v12 release.

But the previous implementation added some bloat to parsers due to the syntax ambiguity, e.g., apply(~param).
And for bitwise-OR (|), I'm not sure if it's even possible to add without breaking changes on the critical syntax like pattern matching.

Keeping our syntax as simple as possible is really important for parser maintainability and reproducibility. Being overly reliant on context can lead to broken syntax highlighting.

So we discussed alternative syntax for binary operators, imported from F# again.

https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/#bitwise-operators

  • ~~~ for bitwise NOT
  • ||| for bitwise OR
  • &&& for bitwise AND
  • ^^^ for bitwise XOR

(& and ^ operators could be handled without any ambiguity, but for consistency)

Basically using dedicated tokens for each operator eliminates almost all complexity.

More characters, more noises. But they at least make it easier to work with than using stdlib functions without any operator support.

Copy link

pkg-pr-new bot commented Sep 16, 2025

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript-lang/rescript@7894

@rescript/darwin-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-arm64@7894

@rescript/darwin-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-x64@7894

@rescript/linux-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-arm64@7894

@rescript/linux-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-x64@7894

@rescript/runtime

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/runtime@7894

@rescript/win32-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/win32-x64@7894

commit: 8a8ffa0

let rbt = make((~compare))
let rbt = make((~-compare) ^ ~x)
let rbt = make(~~~compare)
let rbt = make(~~~-compare ^^^ ~~~x)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps enforcing parens for nested unary application would look better.

Copy link
Member Author

@cometkim cometkim Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or any case when it's a right-hand operand?

-make(~~~-compare ^^^ ~~~x)
+make(~~~(-compare) ^^^ (~~~x))

@@ -151,8 +151,9 @@ let is_atomic_typ_expr_start = function
let is_expr_start = function
| Token.Assert | At | Await | Backtick | Bang | Codepoint _ | False | Float _
| For | Hash | If | Int _ | Lbrace | Lbracket | LessThan | Lident _ | List
| Lparen | Minus | MinusDot | Module | Percent | Plus | PlusDot | Tilde
| String _ | Switch | True | Try | Uident _ | Underscore (* _ => doThings() *)
| Lparen | Minus | MinusDot | Module | Percent | Plus | PlusDot | Bnot | Bor
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this was not all part of this PR, but

| BitwiseNot
| BitwiseOr
| BitwiseXor
| BitwiseAnd 

would read better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or actually, should it not be

| TildeTildeTilde
| BarBarBar
| CaretCaretCaret
| AndAndAnd

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if there is a possibility to reuse that tokens across the grammar, I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice for consistency, as we already have DotDotDot and EqualEqualEqual, too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in this spirit, I would also keep Tilde.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know. we already have tokens like Land, Lor. Do you want to change those token names too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or leave them as is, as Christoph said it would just be nice to have.

@cristianoc
Copy link
Collaborator

This seems like a decent compromise. At least, it's clean.
The only downside is that it looks a bit ugly.
So there's not much space for design, as the implementation is straightforward.
The only decision needed is a yes/no. How about a quick poll to see what people think?

| '&', '&' ->
next3 scanner;
Token.Band
| '&', _ ->
next2 scanner;
Token.Land
| _ ->
next scanner;
Token.Band)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be another token.

@jderochervlk
Copy link
Contributor

The only decision needed is a yes/no. How about a quick poll to see what people think?

I'm in favor of this. It might seem ugly at first glance, but if you look at the f# docs with them all on a nice table it does make sense and seems less ugly.

https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/bitwise-operators

@zth zth added this to the v12 milestone Sep 18, 2025
@cometkim
Copy link
Member Author

The only decision needed is a yes/no. How about a quick poll to see what people think?

You mean to support bitwise operators or not?

@cometkim
Copy link
Member Author

The only downside is that it looks a bit ugly.

Let's take a problematic(?) example:

value >> 4 &&& field === 0

The impression is that &&& feels the most "heavy" visually.

@cometkim
Copy link
Member Author

+  Syntax error!
+  syntax_tests/data/parsing/grammar/typedefinition/polyvariant.res:45:10-11
+
+  43 │ | #B(int, int)
+  44 │ | #C(float)
+  45 │ | #D(int) & (string)
+  46 │ | #E(int, int) & (string, string, string) & (float)
+  47 │ | #F & (string)
+
+  Did you forget a `]` here?

What's & here? Is it a live feature we have?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants