将 2014 Nim 翻译成 2019 Nim
translating 2014 Nim to 2019 Nim
我偶然发现这段代码为 html 定义了 DSL:
template html(matter: stmt) {.dirty.} =
var result = ""
matter
template tag(tagName) =
template `tagName`(attrs: varargs[expr], matter: stmt = nil) {.dirty.} =
# formatAttrs closes the tag and adds the inner tag if necessary
result.add("<" & astToStr(tagName) & formatAttrs(attrs))
matter
result.add("</" & astToStr(tagName) & ">")
tag head; tag link; tag body
tag ul; tag li; tag title
tag p; tag h2
template css(file) {.dirty.} =
link(relation = "stylesheet", href = file)
macro formatAttrs(args: seq[expr]): expr =
result = newCall("&")
var innerTexts = newSeq[string]()
for arg in args:
if arg.kind == nnkExprEqExpr:
result.addParams($arg[0], "=", quoteString($arg[1]))
else:
innerTexts.add($arg)
result.addParams ">"
result.addParams innerTexts
使用方法是这样的:
type Article = object
title, body: string
proc myPage(articles: seq[Article]): string =
return html:
head:
title "govnokod.ru"
css "moar-blink.css"
body:
ul:
for article in articles:
li:
h2 article.title
p article.body
模板扩展后期望的最终结果是这个 Nim 代码:
proc myPage(articles: seq[Article]): string =
var result = ""
result.add("<" & "head" & ">")
result.add("<" & "title" & ">")
result.add("govnokod.ru")
result.add("</" & "title" & ">")
result.add("<link " & "relation" & "=" & "\"stylesheet\"" &
"href" & "=" & "\"moar-blink.css\"" & ">")
result.add("</" & "link" & ">")
result.add("</" & "head" & ">")
result.add("<" & "body" & ">")
result.add("<" & "ul" & ">")
for article in articles:
result.add("<" & "li" & ">")
result.add("<" & "h2" & ">")
result.add article.title
result.add("</" & "h2" & ">")
result.add("<" & "p" & ">")
result.add article.body
result.add("</" & "p" & ">")
result.add("</" & "li" & ">")
result.add("</" & "ul" & ">")
result.add("</" & "body" & ">")
我在这些幻灯片中找到了它:
http://ibob.github.io/slides/nimrodbg/#/12
还用到了表达式模式匹配:
http://ibob.github.io/slides/nimrodbg/#/16
template optAdd1 {x = y; x.add(z)} (x, y, z: string) =
x = y & z
template optAdd2 {x.add(y); x.add(z)} (x, y, z: string) =
x.add(y & z)
因此最终的 C 代码最终与此等价(没有不必要的字符串连接):
NimString myPage(const Sequence<Article>& articles) {
NimString result =
"<head><title>govnokod.ru</title>"
"<link relation=\"\stylesheet\" href=\"moar-blink.css\></link></head>"
"<body><ul>";
for(const auto& article: articles) {
result.add(Concat("<li><h2>",
article.title, "</h2><p>",
article.body, "</p></li>"));
}
result.add("</ul></body>");
return result;
}
这是 5 年前的 Nim 语法 - 在 2019 年会是什么样子?一切还可能吗?我熟悉 Nim 的基础知识,但如果我在向其他人展示该语言时了解它的最新情况,我真的很想使用这个示例。
编辑:感谢@xbello,我让它工作了!
import macros, strformat, strutils
template tag(tagName) =
template `tagName`(body: untyped) =
result.add("<" & astToStr(tagName) & ">")
body
result.add("</" & astToStr(tagName) & ">")
template `tagName`(attrs: varargs[untyped]) =
result.add("<" & astToStr(tagName) & " " & formatAttrs(attrs))
result.add("</" & astToStr(tagName) & ">")
template `tagName`(content: string) =
result.add("<" & astToStr(tagName) & ">" & content)
result.add("</" & astToStr(tagName) & ">")
macro formatAttrs(args: varargs[untyped]): untyped =
result = newCall("&")
var arg_list: seq[string] = @[]
for arg in args:
if arg.kind == nnkExprEqExpr:
arg_list.add(&"{arg[0]}=\"{arg[1]}\"")
arg_list.add(">")
result.add(newLit(join(arg_list, " ")))
template html(matter: untyped) =
result = "<html>"
matter
result.add("</html>")
template css(file) =
link(relation = "stylesheet", href = file)
tag head; tag link; tag body
tag ul; tag li; tag title
tag p; tag h2
type Article = object
title, body: string
proc myPage(articles: seq[Article]): string =
html:
head:
title "govnokod.ru"
css "moar-blink.css"
body:
ul:
for article in articles:
li:
h2 article.title
p article.body
let articles = @[Article(title: "omg", body: "omg_body"), Article(title: "wtf", body: "wtf_body")]
echo myPage(articles)
这是我使它正常工作的唯一方法。模板分为仅正文 (head)、attrs (link) 和内容 (li):
template tag(tagName) =
template `tagName`(body: untyped) =
result.add("<" & astToStr(tagName) & ">")
body
result.add("</" & astToStr(tagName) & ">")
template `tagName`(attrs: varargs[untyped]) =
result.add("<" & astToStr(tagName) & " " & formatAttrs(attrs))
result.add("</" & astToStr(tagName) & ">")
template `tagName`(content: string) =
result.add("<" & astToStr(tagName) & ">" & content)
result.add("</" & astToStr(tagName) & ">")
宏写成这样(需要import strformat
和strutils
):
macro formatAttrs(args: varargs[untyped]): untyped =
result = newCall("&")
var arg_list: seq[string] = @[]
for arg in args:
if arg.kind == nnkExprEqExpr:
arg_list.add(&"{arg[0]}=\"{arg[1]}\"")
arg_list.add(">")
result.add(newLit(join(arg_list, " ")))
我偶然发现这段代码为 html 定义了 DSL:
template html(matter: stmt) {.dirty.} =
var result = ""
matter
template tag(tagName) =
template `tagName`(attrs: varargs[expr], matter: stmt = nil) {.dirty.} =
# formatAttrs closes the tag and adds the inner tag if necessary
result.add("<" & astToStr(tagName) & formatAttrs(attrs))
matter
result.add("</" & astToStr(tagName) & ">")
tag head; tag link; tag body
tag ul; tag li; tag title
tag p; tag h2
template css(file) {.dirty.} =
link(relation = "stylesheet", href = file)
macro formatAttrs(args: seq[expr]): expr =
result = newCall("&")
var innerTexts = newSeq[string]()
for arg in args:
if arg.kind == nnkExprEqExpr:
result.addParams($arg[0], "=", quoteString($arg[1]))
else:
innerTexts.add($arg)
result.addParams ">"
result.addParams innerTexts
使用方法是这样的:
type Article = object
title, body: string
proc myPage(articles: seq[Article]): string =
return html:
head:
title "govnokod.ru"
css "moar-blink.css"
body:
ul:
for article in articles:
li:
h2 article.title
p article.body
模板扩展后期望的最终结果是这个 Nim 代码:
proc myPage(articles: seq[Article]): string =
var result = ""
result.add("<" & "head" & ">")
result.add("<" & "title" & ">")
result.add("govnokod.ru")
result.add("</" & "title" & ">")
result.add("<link " & "relation" & "=" & "\"stylesheet\"" &
"href" & "=" & "\"moar-blink.css\"" & ">")
result.add("</" & "link" & ">")
result.add("</" & "head" & ">")
result.add("<" & "body" & ">")
result.add("<" & "ul" & ">")
for article in articles:
result.add("<" & "li" & ">")
result.add("<" & "h2" & ">")
result.add article.title
result.add("</" & "h2" & ">")
result.add("<" & "p" & ">")
result.add article.body
result.add("</" & "p" & ">")
result.add("</" & "li" & ">")
result.add("</" & "ul" & ">")
result.add("</" & "body" & ">")
我在这些幻灯片中找到了它: http://ibob.github.io/slides/nimrodbg/#/12
还用到了表达式模式匹配: http://ibob.github.io/slides/nimrodbg/#/16
template optAdd1 {x = y; x.add(z)} (x, y, z: string) =
x = y & z
template optAdd2 {x.add(y); x.add(z)} (x, y, z: string) =
x.add(y & z)
因此最终的 C 代码最终与此等价(没有不必要的字符串连接):
NimString myPage(const Sequence<Article>& articles) {
NimString result =
"<head><title>govnokod.ru</title>"
"<link relation=\"\stylesheet\" href=\"moar-blink.css\></link></head>"
"<body><ul>";
for(const auto& article: articles) {
result.add(Concat("<li><h2>",
article.title, "</h2><p>",
article.body, "</p></li>"));
}
result.add("</ul></body>");
return result;
}
这是 5 年前的 Nim 语法 - 在 2019 年会是什么样子?一切还可能吗?我熟悉 Nim 的基础知识,但如果我在向其他人展示该语言时了解它的最新情况,我真的很想使用这个示例。
编辑:感谢@xbello,我让它工作了!
import macros, strformat, strutils
template tag(tagName) =
template `tagName`(body: untyped) =
result.add("<" & astToStr(tagName) & ">")
body
result.add("</" & astToStr(tagName) & ">")
template `tagName`(attrs: varargs[untyped]) =
result.add("<" & astToStr(tagName) & " " & formatAttrs(attrs))
result.add("</" & astToStr(tagName) & ">")
template `tagName`(content: string) =
result.add("<" & astToStr(tagName) & ">" & content)
result.add("</" & astToStr(tagName) & ">")
macro formatAttrs(args: varargs[untyped]): untyped =
result = newCall("&")
var arg_list: seq[string] = @[]
for arg in args:
if arg.kind == nnkExprEqExpr:
arg_list.add(&"{arg[0]}=\"{arg[1]}\"")
arg_list.add(">")
result.add(newLit(join(arg_list, " ")))
template html(matter: untyped) =
result = "<html>"
matter
result.add("</html>")
template css(file) =
link(relation = "stylesheet", href = file)
tag head; tag link; tag body
tag ul; tag li; tag title
tag p; tag h2
type Article = object
title, body: string
proc myPage(articles: seq[Article]): string =
html:
head:
title "govnokod.ru"
css "moar-blink.css"
body:
ul:
for article in articles:
li:
h2 article.title
p article.body
let articles = @[Article(title: "omg", body: "omg_body"), Article(title: "wtf", body: "wtf_body")]
echo myPage(articles)
这是我使它正常工作的唯一方法。模板分为仅正文 (head)、attrs (link) 和内容 (li):
template tag(tagName) =
template `tagName`(body: untyped) =
result.add("<" & astToStr(tagName) & ">")
body
result.add("</" & astToStr(tagName) & ">")
template `tagName`(attrs: varargs[untyped]) =
result.add("<" & astToStr(tagName) & " " & formatAttrs(attrs))
result.add("</" & astToStr(tagName) & ">")
template `tagName`(content: string) =
result.add("<" & astToStr(tagName) & ">" & content)
result.add("</" & astToStr(tagName) & ">")
宏写成这样(需要import strformat
和strutils
):
macro formatAttrs(args: varargs[untyped]): untyped =
result = newCall("&")
var arg_list: seq[string] = @[]
for arg in args:
if arg.kind == nnkExprEqExpr:
arg_list.add(&"{arg[0]}=\"{arg[1]}\"")
arg_list.add(">")
result.add(newLit(join(arg_list, " ")))