# std/macrocache

Theme:

- Manual
- Standard library
- Index
- Compiler docs
- Fusion docs
- devel, stable

Search:
Source Edit

This module provides an API for macros to collect compile-time information across module boundaries. It should be used instead of global `{.compileTime.}` variables as those break incremental compilation.

The main feature of this module is that if you create `CacheTable`s or any other `Cache` types with the same name in different modules, their content will be shared, meaning that you can fill a `CacheTable` in one module, and iterate over its contents in another.

Example:

    import std/macrocache
    import std/macros

    const mcTable = CacheTable"myTable"
    const mcSeq = CacheSeq"mySeq"
    const mcCounter = CacheCounter"myCounter"

    static:
      # add new key "val" with the value `myval`
      let myval = newLit("hello ic")
      mcTable["val"] = myval
      assert mcTable["val"].kind == nnkStrLit

    # Can access the same cache from different static contexts
    # All the information is retained
    static:
      # get value from `mcTable` and add it to `mcSeq`
      mcSeq.add(mcTable["val"])
      assert mcSeq.len == 1

    static:
      assert mcSeq[0].strVal == "hello ic"

      # increase `mcCounter` by 3
      mcCounter.inc(3)
      assert mcCounter.value == 3

# Types

    CacheCounter = distinct string

  Compile-time counter, uses `int` for storing the count. Source Edit

    CacheSeq = distinct string

  Compile-time sequence of `NimNode`s. Source Edit

    CacheTable = distinct string

  Compile-time table of key-value pairs.

  Keys are `string`s and values are `NimNode`s.

  Source Edit

# Procs

    proc `[]`(s: CacheSeq; i: BackwardsIndex): NimNode {....raises: [], tags: [],
        forbids: [].}

  Returns the `i`th last value from `s`.

  Example:

      import std/macros

      const mySeq = CacheSeq"backTest"
      static:
        mySeq &= newLit(42)
        mySeq &= newLit(7)
        assert mySeq[^1].intVal == 7  # Last item
        assert mySeq[^2].intVal == 42 # Second last item

  Source Edit

    proc `[]`(s: CacheSeq; i: int): NimNode {.magic: "NcsAt", ...raises: [], tags: [],
        forbids: [].}

  Returns the `i`th value from `s`.

  Example:

      import std/macros

      const mySeq = CacheSeq"subTest"
      static:
        mySeq.add(newLit(42))
        assert mySeq[0].intVal == 42

  Source Edit

    proc `[]`(t: CacheTable; key: string): NimNode {.magic: "NctGet", ...raises: [],
        tags: [], forbids: [].}

  Retrieves the `NimNode` value at `t[key]`.

  Example:

      import std/macros

      const mcTable = CacheTable"subTest"
      static:
        mcTable["toAdd"] = newStmtList()

        # get the NimNode back
        assert mcTable["toAdd"].kind == nnkStmtList

  Source Edit

    proc `[]=`(t: CacheTable; key: string; value: NimNode) {.magic: "NctPut",
        ...raises: [], tags: [], forbids: [].}

  Inserts a `(key, value)` pair into `t`.
  Warning: `key` has to be unique! Assigning `value` to a `key` that is already in the table will result in a compiler error.

  Example:

      import std/macros

      const mcTable = CacheTable"subTest"
      static:
        # assign newLit(5) to the key "value"
        mcTable["value"] = newLit(5)

        # check that we can get the value back
        assert mcTable["value"].kind == nnkIntLit

  Source Edit

    proc add(s: CacheSeq; value: NimNode) {.magic: "NcsAdd", ...raises: [], tags: [],
                                            forbids: [].}

  Adds `value` to `s`.

  Example:

      import std/macros
      const mySeq = CacheSeq"addTest"

      static:
        mySeq.add(newLit(5))
        mySeq.add(newLit("hello ic"))

        assert mySeq.len == 2
        assert mySeq[1].strVal == "hello ic"

  Source Edit

    proc contains(t: CacheTable; key: string): bool {.inline, ...raises: [], tags: [],
        forbids: [].}

  Alias of hasKey for use with the `in` operator.

  Example:

      import std/macros
      const mcTable = CacheTable"containsEx"
      static:
        mcTable["foo"] = newEmptyNode()
        # Will be true since we gave it a value before
        assert "foo" in mcTable

  Source Edit

    proc hasKey(t: CacheTable; key: string): bool {....raises: [], tags: [],
        forbids: [].}

  Returns true if `key` is in the table `t`.

  See also:

  - contains proc for use with the `in` operator

  Example:

      import std/macros
      const mcTable = CacheTable"hasKeyEx"
      static:
        assert not mcTable.hasKey("foo")
        mcTable["foo"] = newEmptyNode()
        # Will now be true since we inserted a value
        assert mcTable.hasKey("foo")

  Source Edit

    proc inc(c: CacheCounter; by = 1) {.magic: "NccInc", ...raises: [], tags: [],
                                        forbids: [].}

  Increments the counter `c` with the value `by`.

  Example:

      static:
        let counter = CacheCounter"incTest"
        inc counter
        inc counter, 5

        assert counter.value == 6

  Source Edit

    proc incl(s: CacheSeq; value: NimNode) {.magic: "NcsIncl", ...raises: [], tags: [],
        forbids: [].}

  Adds `value` to `s`.
  Hint: This doesn't do anything if `value` is already in `s`.

  Example:

      import std/macros
      const mySeq = CacheSeq"inclTest"

      static:
        mySeq.incl(newLit(5))
        mySeq.incl(newLit(5))

        # still one element
        assert mySeq.len == 1

  Source Edit

    proc len(s: CacheSeq): int {.magic: "NcsLen", ...raises: [], tags: [], forbids: [].}

  Returns the length of `s`.

  Example:

      import std/macros

      const mySeq = CacheSeq"lenTest"
      static:
        let val = newLit("helper")
        mySeq.add(val)
        assert mySeq.len == 1

        mySeq.add(val)
        assert mySeq.len == 2

  Source Edit

    proc len(t: CacheTable): int {.magic: "NctLen", ...raises: [], tags: [],
                                   forbids: [].}

  Returns the number of elements in `t`.

  Example:

      import std/macros

      const dataTable = CacheTable"lenTest"
      static:
        dataTable["key"] = newLit(5)
        assert dataTable.len == 1

  Source Edit

    proc value(c: CacheCounter): int {.magic: "NccValue", ...raises: [], tags: [],
                                       forbids: [].}

  Returns the value of a counter `c`.

  Example:

      static:
        let counter = CacheCounter"valTest"
        # default value is 0
        assert counter.value == 0

        inc counter
        assert counter.value == 1

  Source Edit

# Iterators

    iterator items(s: CacheSeq): NimNode {....raises: [], tags: [], forbids: [].}

  Iterates over each item in `s`.

  Example:

      import std/macros
      const myseq = CacheSeq"itemsTest"

      static:
        myseq.add(newLit(5))
        myseq.add(newLit(42))

        for val in myseq:
          # check that all values in `myseq` are int literals
          assert val.kind == nnkIntLit

  Source Edit

    iterator pairs(t: CacheTable): (string, NimNode) {....raises: [], tags: [],
        forbids: [].}

  Iterates over all `(key, value)` pairs in `t`.

  Example:

      import std/macros
      const mytabl = CacheTable"values"

      static:
        mytabl["intVal"] = newLit(5)
        mytabl["otherVal"] = newLit(6)
        for key, val in mytabl:
          # make sure that we actually get the same keys
          assert key in ["intVal", "otherVal"]

          # all vals are int literals
          assert val.kind == nnkIntLit

  Source Edit