Implementing New Operators

Some time ago, maybe 1.18.0, as an alternative to the standard range syntax, I implemented

i .. j :: k

and I think

i .. j .:. k

to get a bit closer to the Fortran syntax for a range

i : j : k

and the Fortran user seemed happy.

I simply mapped :: to the same token as by, i.e. TBY.

I tried to use it with 1.33.0 and while the syntax analysis works, it now wants a procedure called '::' or .:.. How is such a thing handled now?

Also, I tried to implement a new operator +@' to mean the same (for now) as addition. But it wants a procedure +@` now. I cannot just map that symbol to TPLUS. How does this work. Eventually I will make it do augmented addition.

Ditto for new comparison predicates ?? and !??

Where is this sort of stuff explained?

Thanks - Damian

Hi Damian,

I'm not sure there's a nice explanation of how the parser works that I can link you. However, I did note a couple of productions in the parser that use the string value of the token, which would correspond to the behavior you're seeing with wanting a procedure called '::'.

Here's the production for 'by' in chpl.ypp:

| expr TBY expr            { $$ = context->buildBinOp(@$, $1, $2, $3); }
//               the string in TBY is passed as argument here ^
//               this is the string "by" or ".:." depending on which token was used

The same is true for all the other binary operations you're trying to define.

A quick-and-dirty solution since you already have it emitting TBY tokens (e.g.) would be to create a new production instead of using TBY directly, and force it to always return the string "by".

  TBY { $$ = PODUniqueString::get(context->context(), "by"); }

// ...

| expr by_operator expr    { $$ = context->buildBinOp(@$, $1, $2, $3); }

Which should achieve your goal of making .:. literally mean the by token.

The next-less-quick step is to define your own tokens for these new operators in the same way the TBY tokens etc. are defined, and then convert them into the production AST after parsing. This way, you can still eventually convert the .:. operator into by, but for your other operators (+@, for example), you can treat them as regular operators and even allow overloading etc. Let me know if you would like guidance on how to do that, as it involves a couple more spots in the compiler.