如何解决Nim 宏:如何命名正文参数
我一直在尝试制作 Neel 的更改版本,它使用 Jester 并添加了功能。在注册了一些可以方便地从前端调用的程序后,您可以使用一个名为 startApp
的宏启动 Neel 应用程序,该宏具有以下签名:
macro startApp*(startURL,assetsDir: string,portNo: int = 5000,position: array[2,int] = [500,150],size: array[2,int] = [600,600],chromeFlags: seq[string] = @[""],appMode: bool = true) =
...
startApp
创建一个带有 router
宏和一些硬编码路由的 Jester 路由器:
router theRouter:
get "/":
resp(Http200,NOCACHE_HEADER,readFile(getCurrentDir() / `assetsDir` / startURL`))#is this most efficient?
get "/neel.js":
...
现在我一直在尝试修改它并添加一个参数以允许 startApp
的调用者通过一个无类型的“body”类型的参数传入额外的路由(是否有一个名称,通过路?),就像这样:
macro startApp*(startURL,appMode: bool = true,extraRoutes : untyped
)=
...所以你可以这样做
startApp(startUrl="index.html",assetsDir="web",appMode=false):
get "/extra.js":
resp(Http200,`noCacheHeader`,"console.log('loaded extra.js')")
post "/login":
...
但是现在上面的代码导致了一个错误
Error: type mismatch: got <string,void>
but expected one of:
proc get[T](self: Option[T]): lent T
first type mismatch at position: 1
这意味着编译器正在尝试评估 get
表达式,而不是简单地将其未处理的语法树传递到 startApp
中,这与无类型宏参数的整点相反。我发现如果传递所有参数,它就可以正常工作。所以我想我没有命名身体的事实导致 Nim 认为我必须尝试将它传递给 portNo 或其他东西。很公平。但是我现在该怎么办?有什么办法可以像 extraRoutes=...
一样吗?我尝试执行 extraRoutes=quote do: ...
和类似的操作,但找不到任何有效的方法。
所以……这能解决吗?或者我是否必须像手动传递默认参数的副本那样进行黑客攻击?
如果您有更好的想法来实现这一点,我很乐意,但请详细说明。我总共花了大约五个小时,我已经尝试过例如事先制作了一个 StmtList
而不是将这个额外的路由业务捆绑在 startApp
中,但放弃了,因为错误更加神秘。
解决方法
解决方案 1
默认参数可以传递给宏,但对于块来说,它似乎不是特别漂亮:
import std/macros
macro optArgs(arg1: static[string],arg2: static[string] = "hello",arg3: typed = nil,body: untyped = nil) =
if not isNil(body):
echo body.treeRepr()
optArgs(
"test",body = (
quote do:
some untyped arguments that are not checked
)
)
optArgs("test")
optArgs("test",arg3 = int)
optArgs("test",body = int)
输出
Call
Ident "quote"
StmtList
Command
Command
Ident "some"
Command
Ident "untyped"
Command
Ident "arguments"
Command
Ident "that"
Ident "are"
Prefix
Ident "not"
Ident "checked"
NilLit
NilLit
Ident "int"
如果您想使用 call(<arguments>): body
语法传递代码块,我建议采用以下方法:接受元组的语法(可以混合位置参数和命名参数)并自己进行一些后处理。在这种特殊情况下,您将获得 (Par (Ident "positional") (ExprColonExpr (Ident "test") (IntLit 123)))
作为参数列表,可以对其进行处理以获得必要的参数,或者您可以调用 error 以指示误用。
macro namedArgs(arglist: untyped,body: untyped) =
echo argList.lispRepr()
namedArgs (positional,test: 123):
echo "ACtual body"
解决方案 2
应该注意的一件事是,如果参数传递不正确(如 Error: undeclared identifier: 'positional'
),类似元组的参数方法会产生相当神秘的错误。这可以使用
macro vras(arglist: varargs[untyped]) =
echo argList.lispRepr()
vras(positional,test = 123):
echo "ACtual body"
结果为您提供了以下树,但在这种情况下,您必须手动实现所有参数处理。
Arglist
Ident "positional"
ExprEqExpr
Ident "test"
IntLit 123
StmtList
Command
Ident "echo"
StrLit "ACtual body"
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。