'<-' (not) useable as binary operator? Preprocessor workaround?

Contrast

1--2 
// The preceding error dump is for ERROR: Message '--' not understood.
// RECEIVER: 1

Which is usual stuff you get from undefined operators (for a given receiver class), easily customized/extended in the usual manner. (I actually have that -- defined/customized to do rrand on numbers, if you’re curious.)

On the other hand, although a cursory check puts <- in the same “syntactic” category as --

'--'.isBinaryOp // -> true
'<-'.isBinaryOp // -> true

Trying to actually use the latter as a binary operator is much more troublesome:

1 <- 2 

ERROR: syntax error, unexpected LEFTARROW, expecting $end
  in interpreted text
  line 1 char 4:

  1 <- 2 
    ^^
-----------------------------------
ERROR: Command line parse failed

So clearly that won’t work with the standard parser. I guess a (custom) preprocessor could turn those into explicit BinaryOpFunction calls because that puts us on the well-trodden path thereafter:

BinaryOpFunction('<-', 1, 2).value

// The preceding error dump is for ERROR: Message '<-' not understood.
// RECEIVER: 1

Has anyone experienced doing such (seemingly fairly simple) operator replacement/expansions from the preprocessor hook? Does such stuff work? As far as I can tell the preprocessor doesn’t have access to the later AST, so complex expressions could fail with a totally trivial approach, e.g. . (dot) binds tighter that binops and so do brackets. Contrary to the saying in some guides that there is no operator precedence in SC, the is actually some, just not between most binary operators. So that modicum of precedence would have to be properly accounted for even in a fairly simple operator replacement with a function call.

1 + 2.neg // -> -1

a = [5, 9]
[1] +.s a[1] // -> [ 10 ] 
[1] +.s a@@1 // -> 6
[1] +.s (a@@1) // -> [ 10 ]

So, has anyone tried to do this task of (properly, precedence-wise) replacing operators (“forbidden” or otherwise) with function calls?

If not, is there some place in the parser code I can look at to see what binds tighter than binary operators? (I did discover . and brackets by myself as belonging to that category.)


Actually, there’s a somewhat simpler workaround, replacing <- with another string that is an operator that the parser can grok, e.g.

1<-|2 

gives the usual complaint about Message '<-|' not understood rather than the odd parser complaint about LEFTARROW.

And to answer at least for myself that “mystery”, after grepping the Bison code, the (only) SC syntactic context that uses that LEFTARROW token is list comprehensions, e.g.

all {:[x,y], x <- (1..5), y <- (1..x), (x+y).isPrime }

i don’t have answers to all your questions, but just wanted to say that you are correct that <- is only allowed in a list comprehension expression. isBinaryOp is not particularly well-defined in respect to list comprehensions, but i would venture that since = is one special case for which isBinaryOp returns false, that <- should be treated the same. it’s also possible that <- could be allowed outside of a list comprehension expression without any downside.

i have not thought through either of these cases far enough to offer anything more than that conjecture.

As far as I can tell the preprocessor doesn’t have access to the later AST

this is correct, the pipeline is roughly:

  • preprocessing
  • lexing
  • parsing (i.e. AST generation)
  • semantic analysis
  • bytecode emission
1 Like