/
02.05.2025 at 10:38 pm
Cuttings

let x = 1; y = 2; z = 3
logvars(x, y, z)

# Output: x = 1, y = 2, z = 3

  • Use macro logvars(args: varargs[untyped]).
  • Loop over args and emit an echo.
  1. Two different macro approaches: logvars1 is more idiomatic for Nim; logvars2 is educationally rich.

  2. Use astToStr inside macros, to to convert each variable to a "(identifier) = " string dynamically.

    1. Accessing identifiers via backticks.

    2. stdout.write for fine-grained control (like Python's end=" ").

    3. quote do: captures whole statements. Conditional logic must live outside it.

  3. Distinction between AST construction, vs runtime evaluation, i.e: You're not running code - you're building the structure of it, piece by piece - i.e. constructing formatted expressions via formatted_parts, to be spliced into actual Nim code later. This makes the macro logic easier to follow especially when debugging or extending it.

  4. You're assembling output in result using stdout.write. You're making decisions outside the quote do.

Code (SolutiON)
     import macros

# ATTEMPT-1

macro logvars1(args: varargs[untyped]): untyped =
  result = newStmtList()
  var parts: seq[NimNode] = @[]
  for arg in args:
    parts.add(newStrLitNode($arg & " = "))
    parts.add(arg)
    parts.add(newStrLitNode(", "))
  if parts.len >= 1:
    discard parts.pop()
  result.add(newCall(ident("echo"), parts))



## ATTEMPT-2

macro logvars2(args: varargs[untyped]): untyped =

  result = newStmtList()

  var parts: seq[NimNode] = @[] # [!] We work on AST nodes, not strings yet
  for arg in args:
    parts.add(arg)

  var formatted_parts: seq[NimNode] = @[]
  for part in parts:
    formatted_parts.add quote do:
      astToStr(`part`) & " = " & $`part`

  for i, c in formatted_parts:

    if i < (formatted_parts.len - 1):
      result.add quote do:
        stdout.write $`c` & ", "
    else:
      result.add quote do:
        stdout.write $`c`

    # Handling last-line
    if i == (formatted_parts.len - 1):
      result.add quote do:
        stdout.write "\n"

let x = 1
let y = 2
let z = 3
logvars1(x, y, z)
logvars2(x, y, z)

                    
Filed under:
#
#
Words: 140 words approx.
Time to read: 0.56 mins (at 250 wpm)
Keywords:
, , , , , , , , ,

Latest Comments

© Wan Zafran. See disclaimer.