Re: How to call a macro from a template with a constructed identifier argument?

2018-03-23 Thread Lando
> Interesting, I guess this works because quote doesn't touch the passed in 
> backticked identifier and this is then returned intact to the template?

Yes. The different meanings of backtick-quoting ("make an identifier" in the 
template, "evaluate in local scope and put here" in the quote block) can be 
pretty confusing: 


import macros

macro defthing(name: untyped): untyped =
  # used this instead of parseStmt
  result = quote do:
let `name` = 1000
  echo "generated code: " & result.repr

template calldefthing(name: untyped): untyped =
  # defthing name # argument is an identifier
  defthing `name Extra` # argument is not an identifier, I'd like to 
evaluate the `name Extra` before the macro is called

calldefthing x
echo $xExtra



Re: How to call a macro from a template with a constructed identifier argument?

2018-03-23 Thread mratsim
In a quote do block, quoted identifier are interpolated with the normal Nim 
syntax.

You actually have to use the normal Nim syntax, which wasn't really evident in 
my own example because echo exist in both.

Basically quote do is equivalent to template + getAST:


import macros

macro defthing(): untyped =
  
  # macro level
  let interpol = 123
  
  # 2. Extra stuff in macro v2"
  result = newStmtList()
  result.add quote do:
# "Runtime level"

echo "yet more thing to do in macro with normal Nim syntax"
let a = 456 + `interpol`
echo a

proc foo(x: int): bool =
  x mod 2 == 0

echo foo(a)
echo foo(`interpol`)

defthing()




Re: How to call a macro from a template with a constructed identifier argument?

2018-03-22 Thread rpowers
Thanks for the suggestions.

@mratsim I had no idea you could put a template inside a macro and get its 
evaluated AST. Cool! This will be very useful.

@Lando Interesting, I guess this works because quote doesn't touch the passed 
in backticked identifier and this is then returned intact to the template? 
Maybe I should treat identifiers-like NimNodes as more of a black box in the 
future to allow this sort of thing.


Re: How to call a macro from a template with a constructed identifier argument?

2018-03-22 Thread Lando
@mratsim: The code needs two changes to work: 


import macros

macro defthing(name: untyped): untyped =
  # used this instead of parseStmt
  result = quote do:
let `name` = 1000

# Now things get really weird: added a dummy argument and things work as 
intended..
template calldefthing(name, t: untyped) =
  defthing `name Extra`

calldefthing(x, y)
echo $xExtra



Re: How to call a macro from a template with a constructed identifier argument?

2018-03-22 Thread mratsim
Normally to do identifier construction of variable you need to use `{.inject.}`

However untyped macro will capture everything and you will have to deal with 
the inject pragma in your macro.

Instead forget about the template and do identifier construction directly in it.


import macros


static: echo "Target macro: "

dumpASTgen():
  let xExtra = 1000

static: echo "#"

macro defthing(name: untyped): untyped =
  echo name.treerepr
  result = newStmtList()
  
  result.add nnkLetSection.newTree(
nnkIdentDefs.newTree(
  newIdentNode($name & "Extra"),
  newEmptyNode(),
  newLit(1000)
)
  )

defthing awesome


echo "xExtra is: " & $awesomeExtra


Now building on your example, if you want to match normal Nim syntax and macro 
calls. Here are 3 ways to do that from within macros and templates:


import macros

macro defthing(name: untyped): untyped =
  echo name.treerepr
  result = newStmtList()
  
  result.add nnkLetSection.newTree(
nnkIdentDefs.newTree(
  newIdentNode($name & "Extra"),
  newEmptyNode(),
  newLit(1000)
)
  )
  
  # 1. Extra stuff in macro v1
  template extraThing(): untyped =
echo "wow extra from template with normal Nim syntax"
  
  result.add getAST(extraThing())
  
  # 2. Extra stuff in macro v2"
  result.add quote do:
echo "yet more thing to do in macro with normal Nim syntax"

template yetyetAnother(name: untyped): untyped =
  
  # 3. Extra stuff in template
  defthing(name)
  echo xExtra * 1337


yetyetAnother(x)



Re: How to call a macro from a template with a constructed identifier argument?

2018-03-22 Thread rpowers
Yes, that compiles, but the macro produces the code


let x = 1000


instead of the code


let xExtra = 1000


I'm trying to get the identifier to be constructed before passing it into the 
macro, but I'm not sure if that's possible.


Re: How to call a macro from a template with a constructed identifier argument?

2018-03-21 Thread mratsim
This works for me on 0.18 and devel


import macros
import strutils

macro defthing(name: untyped): untyped =
  return parseStmt("let $1 = 1000".format(ident($name)))

template calldefthing(name: untyped): untyped =
  # defthing name # argument is an identifier
  defthing `name Extra` # argument is not an identifier, I'd like to 
evaluate the `name Extra` before the macro is called

calldefthing x



How to call a macro from a template with a constructed identifier argument?

2018-03-21 Thread rpowers
I have a macro that creates a type and associated functions, and I'm calling 
that from a template. I want to use identifier construction to append a suffix 
to the template parameter, but the whole backticked AST (instead of the 
constructed identifier) gets passed in to the macro. Is there some way to 
generate an identifier before the macro is evaluated? I've included a 
simplified example below.


macro defthing(name: untyped): untyped =
return parseStmt("let $1 = 1000".format($name.ident))

template calldefthing(name: untyped): untyped {.dirty.} =
defthing name # argument is an identifier
defthing `name Extra` # argument is not an identifier, I'd like to 
evaluate the `name Extra` before the macro is called

calldefthing x