Как использовать slurp / gorge / staticRead / staticExec в каталоге места вызова? - PullRequest
1 голос
/ 28 апреля 2019

Функции времени компиляции slurp / gorge / staticRead / staticExec, похоже, используют каталог исходного файла в качестве рабочего каталога.В большинстве случаев это желаемое поведение, потому что связь исходного кода и ресурсов времени компиляции является фиксированной.Но как я могу использовать эти функции в библиотеке, чтобы они ссылались на ресурсы, предоставленные пользователями?

Пример структуры:

.
├── client
│   ├── client.nim
│   └── resource.data
└── library
    └── library.nim

Я хочу предоставить функцию bundle в библиотеке, что позволяет клиенту вызывать что-то вроде bundle("resource.data").Внутренне библиотека может использовать, например, slurp(givenResourcePath).Однако это не удастся, потому что slurp смотрит вверх resource.data относительно library.nim.Есть ли способ использовать эти функции и обращаться к файлам, относящимся к месту вызова?

Примечание. Я попытался сгенерировать AST, выполняя slurp с помощью шаблона / макроса, но даже если поиск относится к library.nim.

Ответы [ 2 ]

3 голосов
/ 29 апреля 2019

Самый простой способ справиться с этим - использовать вспомогательный шаблон, который использует instantiationInfo для получения исходного пути вызывающей стороны макроса.

Вы можете создать модуль под названием bundles.nim:

import os

macro bundleImpl(userPath, resource: static string): untyped =
  let resourcePath = splitFile(userPath).dir / resource 
  echo "FULL RESOURCE PATH ", resourcePath
  echo "FILE CONTENTS:"
  echo staticRead(resourcePath)

template bundle*(resource: static string) =
  bundleImpl(instantiationInfo(-1, fullPaths = true).filename, resource)

Затем вы можете использовать его из любого модуля ожидаемым образом:

import
  bundles

bundle "test.txt"

Результат в моей системе выглядит примерно так:

FULL RESOURCE PATH /Users/zahary/nim/scratch/test.txt
FILE CONTENTS:
<test.txt contents>
2 голосов
/ 28 апреля 2019

Это можно решить с помощью макроса с помощью небольшого трюка: поиск реализации slurp показывает, что он использует lineinfo узла slurp AST для определения своего рабочего каталога. По умолчанию при создании AST с помощью макроса присоединяется lineinfo, которая ссылается на library.nim, и, следовательно, slurp использует путь к библиотеке. Чтобы изменить поведение, мы можем прочитать lineinfo с места вызова и прикрепить его к узлу slurp:

macro bundle*(resource: string): untyped =
  # create slurp call node
  var slurpCall = newCall(ident "slurp", newStrLitNode resource.strVal)

  # forward callsite lineinfo to affect working directory behavior
  slurpCall.copyLineInfo(resource)

  # embed slurpCall somewhere in output AST
  # ...
...