Splat operator implementation with macros

2022-12-29 Thread SolitudeSF
nsfw macro activity


Splat operator implementation with macros

2022-12-29 Thread yglukhov
Finally got around to test my idea above and here's what it looks like:


import macros

proc addTupleToCall(c: NimNode, t: NimNode, temps: NimNode) =
  let typ = getType(t)
  var s = t
  if t.kind != nnkSym:
# If it's something more complex than sym, store it in
# tmp to avoid double evaluation
s = genSym(nskLet, "tmp")
temps.add newIdentDefs(s, newEmptyNode(), t)
  
  var a = 0
  var b = 0
  if $typ[0] == "tuple":
b = typ.len - 2
  elif $typ[0] == "array":
a = typ[1][1].intVal
b = typ[1][2].intVal
  else:
doAssert(false, "Wrong type")
  
  for i in a .. b:
c.add(newTree(nnkBracketExpr, s, newLit(i)))

macro addToCall(a: untyped, b: varargs[typed]): untyped =
  let tmps = newNimNode(nnkLetSection)
  var isTuple = false
  for i in 0 ..< b.len:
if i mod 2 == 0:
  isTuple = bool(b[i].intVal)
else:
  if isTuple:
addTupleToCall(a, b[i], tmps)
  else:
a.add(b[i])
  newTree(nnkStmtList, tmps, a)

proc addToCallAux(a: NimNode, b: NimNode, isTuple: bool): NimNode =
  var args = @[b, newLit(isTuple)]
  var n = a
  while n.kind == nnkInfix and n[0].kind == nnkIdent:
if $n[0] == "<<<":
  # echo 1
  args.add(n[2])
  args.add(newLit(false))
elif $n[0] == "<<*":
  args.add(n[2])
  args.add(newLit(true))
n = n[1]
  
  result = newCall(bindSym"addToCall", n)
  for i in countdown(args.high, 0):
result.add(args[i])

macro `<<<`*(a: untyped, b: untyped): untyped =
  addToCallAux(a, b, false)

macro `<<*`*(a: untyped, b: untyped): untyped =
  addToCallAux(a, b, true)

when isMainModule:
  proc foo(a, b: int) =
echo "foo ", a, " ", b
  
  echo() <<< 1 <<< 2 <<* (3, 4) <<* [5, 6] <<< 7
  foo() <<< 5 <<< 6


Run


Splat operator implementation with macros

2022-12-20 Thread Hlaaftana
That is fixed in devel


Splat operator implementation with macros

2022-12-20 Thread ElegantBeef
Oh yay, that means we now have the best code linter.


Splat operator implementation with macros

2022-12-20 Thread ElegantBeef
Well they 'work' on typed ast. They dont even respect `{.noRewrite.}`.


Splat operator implementation with macros

2022-12-20 Thread Hlaaftana
Term rewriting macros work on checked AST IIRC


Splat operator implementation with macros

2022-12-20 Thread MichalMarsalek
Is it not possible with some term rewriting macros?


Splat operator implementation with macros

2022-12-20 Thread yglukhov
However something like this should be possible to implement:


someCall() ... scalarParam ..* tupleParam
# expands to
someCall(scalarParam, tupleParam[0], tupleParam[1])


Run


Splat operator implementation with macros

2022-12-19 Thread Araq
Don't mistreat tuples as arrays, use arrays to begin with and the desire for a 
"splat" disappears.


Splat operator implementation with macros

2022-12-19 Thread ElegantBeef
You cannot use a macro inside the call statement as it does not back propagate 
as you'd want, there is no way of adding the expanded ast to the parent ast, it 
either is a `StmtList`, `Bracket` or whatever type of tree you emit, it never 
gets added to the call as a argument.


Splat operator implementation with macros

2022-12-19 Thread resolritter
I'd like to implement an operator `...` such that:


type Point = tuple[x, y: int]
let p1: Point = (2,2)
let p2: Point = (3,3)
echo sum(1, ...p1, ...p2) # expands to sum(1, 2, 2, 3, 3)


Run

Based on , which refers to 
,
 I came up with the following


import macros

macro `...`(t: typed): auto =
  let ty = getTypeImpl(t)
  
  # does not handle non-tuples at the moment
  assert(ty.typeKind == ntyTuple)
  
  var args = newNimNode(nnkArgList)
  for child in ty:
expectKind(child, nnkIdentDefs)
args.add(newDotExpr(t, child[0]))
  
  return args

func sum(xs: varargs[int]): auto =
  result = 0
  for x in xs:
result += x

type Point = tuple[x, y: int]
let p1: Point = (1,1)
let p2: Point = (2,2)
echo sum(...p1, ...p2)


Run

The above program does not compile. That aside, I don't even know if it 
something like that would be feasible because each template instantiation 
produces a separate `ArgList` node and they'd need to be concatenated with the 
rest of the arguments. My gut feel from experimentation is that there's no 
support in the language for this use-case.

I am aware that it's possible to achieve something similar by producing a new 
`Call` node through a macro, as demonstrated by 
 and 
. I am however trying to use a template 
in the **arguments position** and those solutions are about using a template in 
the call position. i.e. those solutions are about calling the function through 
a macro which pre-processes the arguments, but I'd like to have a way of 
producing multiple function arguments from a macro. Is that possible?