Skip to content

Conversation

@b-studios
Copy link
Collaborator

@b-studios b-studios commented Jul 22, 2025

This PR adds a few more infix operators. This is mostly just lexing and parsing so doesn't come with a lot of conceptual cost for the implementation.

A few things are not clear / implemented:

  • we should name things consistently (I actually would like to rename infixAdd to InfixPlus, but this will break a lot of things)
  • is this slowing down the parser? (for precedence it is now deeply nested)
  • is the precedence ok?
  • should pipe left and right be by-name? This might open up some cool usages.
  • right now the new tokens are added as one batch, we might want to clean them up by sorting them somehow
  • I didn't add a === b and a !== b since the tokens === are already used to represent ==, ahhh.

@b-studios b-studios marked this pull request as ready for review July 28, 2025 15:17
case _ =>
val lhs = variable()
peek.kind match {
case `+=` | `-=` | `*=` | `/=` =>
Copy link
Member

Choose a reason for hiding this comment

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

what about <<= and >>=?

Copy link
Collaborator

@dvdvgt dvdvgt left a comment

Choose a reason for hiding this comment

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

We decided to make some changes in the Effekt meeting. Thanks!

Comment on lines +120 to +121
case `<|`
case `|>`
Copy link
Collaborator

Choose a reason for hiding this comment

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

We decided to delete these.

Comment on lines +1024 to +1056
case `||` => "infixOr"
case `&&` => "infixAnd"
case `===` => "infixEq"
case `!==` => "infixNeq"
case `<` => "infixLt"
case `>` => "infixGt"
case `<` => "infixLt"
case `>` => "infixGt"
case `<=` => "infixLte"
case `>=` => "infixGte"
case `+` => "infixAdd"
case `-` => "infixSub"
case `*` => "infixMul"
case `/` => "infixDiv"
case `+` => "infixAdd"
case `+=` => "infixAdd"
case `-` => "infixSub"
case `-=` => "infixSub"
case `*` => "infixMul"
case `*=` => "infixMul"
case `/` => "infixDiv"
case `/=` => "infixDiv"
case `++` => "infixConcat"
case `>>` => "infixShr"
case `<<` => "infixShl"
case `--` => "infixRemove"

case TokenKind.`~` => "infixTilde"
case TokenKind.`~>` => "infixTildeRight"
case TokenKind.`<~` => "infixTildeLeft"
case TokenKind.`|` => "infixPipe"
case TokenKind.`&` => "infixAmp"

case `<|` => "infixPipeLeft"
case `|>` => "infixPipeRight"
case `..` => "infixDotDot"
case `...` => "infixDotDotDot"
case `^^` => "infixHatHat"
case `^` => "infixHat"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use syntactic not semantic names since they can be overloaded anyway.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Claude suggested these names:

case `+`  => "infixPlus"
case `+=` => "infixPlusEq"
case `-`  => "infixMinus"
case `-=` => "infixMinusEq"
case `*`  => "infixStar"
case `*=` => "infixStarEq"
case `/`  => "infixSlash"
case `/=` => "infixSlashEq"
case `++` => "infixPlusPlus"
case `>>` => "infixGreaterGreater"
case `<<` => "infixLessLess"
case `--` => "infixMinusMinus"
case TokenKind.`~`  => "infixTilde"
case TokenKind.`~>` => "infixTildeGreater"
case TokenKind.`<~` => "infixLessTilde"
case TokenKind.`|`  => "infixBar"
case TokenKind.`&`  => "infixAmp"
case `<|`  => "infixLessBar"
case `|>`  => "infixBarGreater"
case `..`  => "infixDotDot"
case `...` => "infixDotDotDot"
case `^^`  => "infixCaretCaret"
case `^`   => "infixCaret"

Copy link
Collaborator

Choose a reason for hiding this comment

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

Of course, please also change the other operator names

Comment on lines +1086 to +1104
// <EXPR>.[<EXPR>, ...]
case `[` =>
val bracket = peek
val arguments = some(expr, `[`, `,`, `]`)
e = MethodCall(e,
IdRef(Nil, "postfixAccess", Span(source, dot.start, bracket.end, Synthesized)),
Nil, arguments.unspan.map(a => ValueArg.Unnamed(a)), Nil,
Span(source, e.span.from, arguments.span.to, Synthesized)
)

case _ =>
val member = idRef()
// method call
if (isArguments) {
val (targs, vargs, bargs) = arguments()
e = Term.MethodCall(e, member, targs, vargs, bargs, span())
} else {
e = Term.MethodCall(e, member, Nil, Nil, Nil, span())
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Extract into separate PR. Needs further discussion, e.g. setting an array. Do we also want a dedicated syntax for that?

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.

4 participants