Skip to content

Implement addCompileTimeExitProc #564

@yglukhov

Description

@yglukhov

Abstract

Implement the following function:

# module std/macros
proc addCompileTimeExitProc*(cb: proc(): NimNode) {.compileTime.} =
  # Schedules `cb` to be executed as if it was a macro call
  # at the end of main module. Appends result of `cb` at the
  # end of main module.

Motivation

No response

Description

It effectively allows to achieve the same results as #563 was proposed for, albeit in a slightly more convoluted way. On the plus side, the implementation of this magic is trivial.

Code Examples

An example of how delayed CT evaluation can be implemented on top of this (no additional compiler help required):

import macros

proc defineDelayed[T](val: T): NimNode = quote: `val`

macro delayedConstPtrAux[T](prc: static[proc(): NimNode]): untyped =
  let s = genSym(nskProc, "delayed")
  result = quote do:
    proc `s`(): pointer
    `s`()

  let bbb = prc
  addCompileTimeExitProc() do() -> NimNode:
    let a = bbb()
    result = quote do:
      proc `s`(): pointer {.inline, stackTrace: off, enforceNoRaises.} =
        const b = `a`
        when compiles(addr b):
          addr b
        else:
          var g {.global.} = `a`
          addr g

template delayedConstPtr*[T](val: T): ptr T =
  # Returns pointer to const data generated from `val` compile-time
  # expression at the end of compilation.
  cast[ptr T](delayedConstPtrAux[T](proc(): NimNode = defineDelayed(val)))

when isMainModule: # Test
  var registry {.compileTime.}: seq[string]
  macro registerSomething*(a: static[string]): untyped =
    registry.add(a)
  proc testRegistry*() =
    let r = delayedConstPtr(registry)
    doAssert($r[] == """@["foo", "bar"]""")
    echo "TEST PASSED"
  testRegistry()
  registerSomething("foo")
  registerSomething("bar")

Backwards Compatibility

It is 100% backward compatible

Implementation

I've posted a PR to demonstrate this, please feel free to play around.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions