2

I have a nim proc that dedents a multiline string based on the whitespace of the first indented line:

import strutils

proc dedent(s: string): string
    {.noSideEffect.} =
    var prefix = ""
    for line in s.splitLines(keepEol=true):
        if prefix == "" and line.len > 0:
            for j in 0..<line.len:
                if line[j] != ' ':
                    prefix = line[0..j-1]
                    break
        if line.startsWith(prefix):
            result.add(line[prefix.len .. high(line)])
        else:
            result.add(line)

when isMainModule:
    echo dedent """
        cat:
          - meow
          - purr

        dog:
          - bark
          - drool
        """

it nicely outputs:

cat:
  - meow
  - purr

dog:
  - bark
  - drool

but inspecting the intermediate C code, I see:

STRING_LITERAL(TM_9amIjLnWbK7OR9aPA8dicbaQ_14, "        cat:\012          - meow\012          - purr\012        \012       "
" dog:\012          - bark\012          - drool\012        ", 112);

so the dedenting is done at run-time. I can add the compileTime pragma to the proc:

proc dedent(s: string): string
    {.noSideEffect,compileTime.} =

and then the C output changes to:

STRING_LITERAL(TM_9amIjLnWbK7OR9aPA8dicbaQ_3, "cat:\012  - meow\012  - purr\012\012dog:\012  - bark\012  - drool\012", 48);

Which is exactly what I want, multi-line strings that are indented to their surrounding on every line, but don't have that extra indentation in the executable.

But adding that pragma, I can no longer access dedent at run-time, e.g. when adding:

    import os
    if paramCount() > 0:
        for i in 1..paramCount():
            echo dedent paramStr(i)

to isMainModule, you get the error:

Error: request to generate code for .compileTime proc: dedent

I looked at the source for splitLines in strutils.nim to see if there was some other pragma that I could apply, but I did not find anything that would work.

I now about the static statement, but would prefer that the compiler optimises this at compile time without me having to sprinkle this in.

How can I get this to work both compile-time as well as run-time without reverting to the use of static? Do I need to compile the proc from a seperate .nim module? Or is there a compiler option, pragma, something else, that I am missing?

Anthon
  • 69,918
  • 32
  • 186
  • 246

2 Answers2

3

You need to pass the --implicitStatic:on flag to the Nim compiler to enable implicit compile time evaluation of procedures.

These procedures cannot have the compileTime pragma.

Anthon
  • 69,918
  • 32
  • 186
  • 246
Reimer Behrends
  • 8,600
  • 15
  • 19
3

To force the evaluate of any expression at compile-time, you can use static in the following way:

when isMainModule:
    echo static(dedent"""
        cat:
          - meow
          - purr

        dog:
          - bark
          - drool
        """)

All expressions assigned to constants are also evaluated at compile-time, so this is another way to achieve the same.

zah
  • 5,314
  • 1
  • 34
  • 31