如何在调用站点的目录中使用slurp/gorge/staticRead/staticExec?
How to use slurp/gorge/staticRead/staticExec in the directory of the callsite?
编译时函数slurp
/gorge
/staticRead
/staticExec
似乎使用源文件的目录作为工作目录。在大多数情况下,这是所需的行为,因为源代码和编译时资源的关系是固定的。但是如何在库中使用这些函数,以便它们引用用户提供的资源?
示例结构:
.
├── client
│ ├── client.nim
│ └── resource.data
└── library
└── library.nim
我想在库中提供一个 bundle
函数,它允许客户端调用类似 bundle("resource.data")
的东西。图书馆内部可以使用例如slurp(givenResourcePath)
。然而这会失败,因为 slurp 查找 resource.data
相对于 library.nim
。有没有办法使用这些函数并引用与调用站点相关的文件?
注意:我试图生成执行 slurp 的 AST template/macro,但即使查找是相对于 library.nim
.
这可以通过使用一个小技巧的宏来解决:查看 slurp
的实现表明它使用 slurp
AST 节点的 lineinfo 来确定其工作目录。默认情况下,使用宏构建 AST 会附加一个引用 library.nim
的 lineinfo,因此,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
# ...
处理此问题的最简单方法是依靠使用 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>
编译时函数slurp
/gorge
/staticRead
/staticExec
似乎使用源文件的目录作为工作目录。在大多数情况下,这是所需的行为,因为源代码和编译时资源的关系是固定的。但是如何在库中使用这些函数,以便它们引用用户提供的资源?
示例结构:
.
├── client
│ ├── client.nim
│ └── resource.data
└── library
└── library.nim
我想在库中提供一个 bundle
函数,它允许客户端调用类似 bundle("resource.data")
的东西。图书馆内部可以使用例如slurp(givenResourcePath)
。然而这会失败,因为 slurp 查找 resource.data
相对于 library.nim
。有没有办法使用这些函数并引用与调用站点相关的文件?
注意:我试图生成执行 slurp 的 AST template/macro,但即使查找是相对于 library.nim
.
这可以通过使用一个小技巧的宏来解决:查看 slurp
的实现表明它使用 slurp
AST 节点的 lineinfo 来确定其工作目录。默认情况下,使用宏构建 AST 会附加一个引用 library.nim
的 lineinfo,因此,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
# ...
处理此问题的最简单方法是依靠使用 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>