编译时函数slurp/gorge/staticRead/staticExec似乎使用源文件的目录作为工作目录。在大多数情况下,这是期望的行为,因为源代码和编译时资源的关系是固定的。但是,我如何在库中使用这些函数,以便它们引用用户提供的资源?
示例结构:
.
├── client
│ ├── client.nim
│ └── resource.data
└── library
└── library.nim我想在库中提供一个bundle函数,它允许客户端调用类似bundle("resource.data")的东西。在内部,库可以使用例如slurp(givenResourcePath)。但是,这将失败,因为slurp查找相对于library.nim的resource.data。有没有办法使用这些函数并引用与调用站点相关的文件?
注意:我尝试使用模板/宏执行slurp来生成AST,但即使这样查找也是相对于library.nim的。
发布于 2019-04-29 20:13:52
处理此问题的最简单方法是依赖帮助器模板,该模板使用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>发布于 2019-04-28 23:13:42
这可以通过一个宏使用一个小技巧来解决:查找slurp的实现显示它使用slurp AST节点的lineinfo来确定其工作目录。默认情况下,使用宏构造一个AST会附加一个引用library.nim的lineinfo,因此,slurp使用库路径。要修改行为,我们可以从callsite读取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
# ...https://stackoverflow.com/questions/55891650
复制相似问题