/
02.05.2025 at 10:38 pm
Cuttings

Log the following using macros:


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

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

Hint:

  • macro logvars(args: varargs[untyped])

  • Loop over args and emit an echo.

  1. I've approached this macro exercise two different ways:

    • logvars1, as being more idiomatic in Nim;
    • logvars2, as an educationally-rich curiosity.
  2. Use astToStr inside macros, to convert each variable to a "(identifier) = " string dynamically:

    1. Access identifiers via backticks.

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

    3. Conditional logic must live outside quote do:, since that syntax captures whole statements.

  3. Distinguish AST construction vs runtime evaluation, i.e: you're not running code - you're building code structure, piece by piece - i.e. and 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 making decisions outside the quote do. Assemble output in the result using stdout.write.

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)

                    
Source: Nim Macros - Beginner & Intermediate Exercises
Filed under:
#
#
Words: 148 words approx.
Time to read: 0.59 mins (at 250 wpm)
Keywords:
, , , , , , , , ,

Potentially related:
  1. A Basic Nim Workflow To Metaprogramming/Macros
  2. Nim Macros - Beginner & Intermediate Exercises
  3. Nim / Exercise - `timed(expr)` macro
  4. Nim / Exercise - `swap(a, b)` macro
  5. Nim / Exercise - `assertPositive(expr)` macro
  6. Nim / Exercise - Make a double(x) macro
  7. But For The Whispers Of Nim
  8. Non-Dissonant Speed Keybindings
  9. Reflections - 43 Things I Learned or Did In 2019

Latest Comments

© Wan Zafran. See disclaimer.