Nim 중홍의 수수께끼 풀기.
22146 단어 macrotutorialnimmetaprogramming
바둑 코끼리 계산을 실현하다
Go에는 변수를 정의하고 키워드 없이 값을 설정하는 조작부호가 있습니다.다음은 Go의 모양새입니다.
a := 300
이것은 Nim에서 매우 간단하게 완성할 수 있지만, 우선 우리가 무엇을 사용해야 하는지 봅시다. dumpTree
import macros
dumpTree:
var a = "Test"
컴파일러는 다음 내용 dumpTree
을 출력하기 때문에 이 코드에 필요한AST를 볼 수 있습니다.StmtList
VarSection
IdentDefs
Ident "a"
Empty
StrLit "Test"
따라서 이 과정을 자동화하려면 Varsection, ident,value가 필요합니다.두 가지 방법을 살펴봅시다.메서드 1
import macros
macro `:=`(name, value: untyped): untyped = newVarStmt(name, value)
비록 우리가 .repr
프로그램을 사용하여 검사를 할 수 있지만, 우리는 확실히 해냈다.import macros
macro `:=`(name, value: untyped): untyped =
result = newVarStmt(name, value)
echo result.repr
a := "Test"
위의 코드를 실행하면 컴파일러가 필요로 하는 것을 볼 수 있습니다 var a = "Test"
방법#2
이 방법은 마찬가지로 간단하지만 아주 좋은 도구를 사용했다.
quote do
코드를 작성할 수 있습니다. 이것은 AST를 생성할 것입니다. 따라서 아래와 같습니다.같은 검사도 위와 같이 진행할 수 있지만, 군더더기를 줄이기 위해서, 나는 그것들을 건너갈 것이다. 왜냐하면 군더기와 자신을 중복하는 것은 군더더기이기 때문이다.import macros
macro `:=`(name, value: untyped): untyped =
quote do:
var `name` = `value`
a := "Test"
치밀한 If 문장을 만들다
때때로 언어의 행동이나 기능을 바꾸고 싶을 때가 있다. 비록 Nim이 문법을 바꾸는 것을 허락하지 않지만, 너는 스스로 블록 논리를 만들 수 있다.그 중 하나는 맞춤형
if
성명이다.다음은 이상적인 실현이다let a = "Yellow"
expandIf:
a == "Hello": echo "Good bye"
a == "Yellow":
echo "Would be a lot cooler if you liked blue."
echo "Yellow sucks"
_: echo "You did not speak."
첫 번째 조건은 if
이고 다음 조건은 elif
이며 마지막_
은 else
지점에 사용된다.이것은 우리의 forfun 실현에 중복된 키워드가 없다는 것을 의미합니다.import macros
dumpTree:
if a == "Hello": echo "Good bye."
elif a == "Yellow":
echo "Would be a lot cooler if you liked blue."
echo "Yellow sucks."
else: echo "You did not speak."
위의 아스트는 보기에 이렇다.StmtList
IfStmt
ElifBranch
Infix
Ident "=="
Ident "a"
StrLit "Hello"
StmtList
Command
Ident "echo"
StrLit "Good bye."
ElifBranch
Infix
Ident "=="
Ident "a"
StrLit "Yellow"
StmtList
Command
Ident "echo"
StrLit "Would be a lot cooler if you liked blue."
Command
Ident "echo"
StrLit "Yellow sucks."
Else
StmtList
Command
Ident "echo"
StrLit "You did not speak."
우리는 또한 우리의 최초expandIf
생각의 주체를 저장하고 우리가 샘플을 채취할 수 있는 결과ast 노드를 볼 수 있다.StmtList
Infix
Ident "=="
Ident "a"
StrLit "Hello"
StmtList
Command
Ident "echo"
StrLit "Good bye"
Infix
Ident "=="
Ident "a"
StrLit "Yellow"
StmtList
Command
Ident "echo"
StrLit "Would be a lot cooler if you liked blue."
Command
Ident "echo"
StrLit "Yellow sucks"
Call
Ident "_"
StmtList
Command
Ident "echo"
StrLit "You did not speak."
이 두 노드를 보면 expandIf
주체에서 ElseIfBranch 노드에 필요한 접미사를 얻을 수 있습니다.만약 우리가 StmtList를 모든 접미사와 분리할 수 있다면, 우리는 newIfStmt
매크로를 사용하여 elif 지점을 생성할 수 있다. 그 중에서 cond
는 접미사이고 body
는StmtList이다.import macros
macro expandIf(statement: untyped): untyped=
var
branches: seq[(NimNode, NimNode)] #Condition, Body
elseBody: NimNode #Else code
for cond in statement:
#Based off the dumpTree, we know this is the else body.
let ifBody = cond.findChild(it.kind == nnkStmtList)
if cond.kind == nnkInfix:
cond.del 3 #Removes Stmtlist
branches.add((cond, ifBody))
elif cond.kind == nnkCall and $cond[0] == "_":
#Based off the dumpTree, we know this is the else body.
elseBody = ifBody
result = newIfStmt(branches) #Generates if stmt
result.add newNimNode(nnkElse).add(elseBody) #Appends else body
echo result.repr
expandIf:
11 == 13 : echo "Test"
12 == 14: echo "Huh"
_ : echo "duh"
위 코드에서 findChild
로 추출한 것을 볼 수 있습니다.cond.del 3
로 StmtList를 삭제하고 마지막으로 if
합니다.우리가 컴파일할 때, 컴파일러는 우리에게 아주 좋은 소식을 보낼 것이다. 감사 echo result.repr
. 이것이 바로 우리가 원하는 완전한 구조의if/else 문장이다.if 11 == 13:
echo "Test"
elif 12 == 14:
echo "Huh"
else:
echo "duh"
비유형 및 유형 매크로
지금까지 우리는 비유형 매크로의 사용법만 연구했는데 이런 매크로는 어떠한 유형 정보도 없고 해석된 후에 우리에게 전달된 매크로이다.다른 종류의 매크로는 유형화 매크로입니다. 이 매크로들은 의미 검사를 거쳤는데 이것은 유형 정보를 가지고 코드가 유효해야 한다는 것을 의미합니다.유형화 매크로는 내성이 필요한 모든 것에 유용하다.
첫 번째 매크로 입력
나에게 부호를 하나 주어라. 나는 너에게 전 세계를 보여줄 것이다.Nim宏에서 기호나'syms'는 스파게티를 만드는 신기한 소스로 의미 검사를 거쳐 내부에 저장된 유형을 의미한다.이런 힘은 만능이다.첫 번째 유형 매크로는 변수를 선언 값으로 재설정하는 매크로입니다.
사용법은 다음과 같습니다.
var a = 100
a *= 3
assert a == 300
resetToDecl(a)
assert a == 100
우선, 우리는 typed
매개 변수가 필요하다는 것을 알고 있기 때문에 우리의 매크로 헤더는 macro resetToDecl(val: typed): untyped
이다.typed
는 untyped
와 매우 비슷하다. 왜냐하면 모든 코드를 받아들이기 때문이다. 그러나 이 예에서 우리는 그것이 의미 검사를 거친 것을 안다.따라서 변수만 처리할 수 있도록 다른 종류의 필터 nnkSym
를 모두 삭제해야 합니다.nifty error
도구를 사용하여 유용한 정보를 제공합니다. 이 메시지는 문자열과 선택할 수 있는 NimNode를 두 번째 인자로 받아들여 오류에 대한 줄 정보를 제공합니다.macro resetToDecl*(val: typed): untyped =
if val.kind == nnkSym:
# We will implement code here later
else:
error("This macro only works with variables." val)
기호는 모든 종류, 과정, 변수가 될 수 있기 때문에, 비var 기호를 필터해야 합니다.네가 알 수 있는 모든 이름.따라서, 우리는 기호의 symKind
를 사용하여 var을 제외한 모든 내용을 필터할 것입니다.macro resetToDecl*(val: typed): untyped =
if val.kind == nnkSym and val.symKind == nskVar:
## We'll continue here in next block
else:
error("This macro only works on variables", val)
우리는 이미 해냈다. 우리는 변수밖에 없다. 그러나 지금의 문제는'우리가 어떻게 성명 성명을 얻는가?!'이다.내성 마법의 힘을 통해!짐의 macros
모듈은 symKind
를 제외한 다른 여러 가지 내성 경로를 제시했는데 getImpl
, getTypeImpl
, getType
등도 있다.우리가 사용할 프로그램은 당연히 getImpl
이다. 왜냐하면 우리는 기호의 실현을 원하기 때문이다(네, 기호가 있어야 합니다. 그렇지 않으면 배터리가 포함되지 않습니다).우리는AST가 어떤 모양인지 빠르게 테스트할 수 있다
echo val.getImpl
. 우리가 본 것은 귀여운 성명이다.IdentDefs
Sym "a"
Empty
IntLit 100
만약 네가 자세히 관찰한다면 이것은 예측할 수 있는 상황이다. 우리가 해야 할 일은 val
를 val.getImpl[^1]
에 분배하는 것이다. 그러므로 우리가 이렇게 하자.macro resetToDecl*(val: typed): untyped =
if val.kind = nnkSym and val.symKind == nskVar:
result = nnkAsgn.newTree(val, val.getImpl[^1])
else:
error("This macro only works with variables", val)
나는 이미 "헤이, 그렇습니까? 이것은 매우 간단합니다. 틀림없이 함정이 있을 것입니까?"네가 옳다. 간단하게 실행하면 var a: int
use에 오류가 발생할 수 있다. Error: illformed AST:
라고 쓰여 있다.이 오류가 발생한 이유는 매크로가 기호의 마지막 항목이 nnkEmpty
인지 확인하지 않았기 때문에, 매크로는 빈 항목만 검사하고, 마지막 항목이 비어 있으면 default(typeof(val))
하나를 보낼 것입니다.다음과 같이 하십시오.
import std/macros
macro resetToDecl*(val: typed): untyped =
if val.kind == nnkSym and val.symKind == nskVar:
let impl = val.getImpl
result = nnkAsgn.newTree(val):
if impl[^1].kind == nnkEmpty:
newCall("default", newCall("typeOf", val))
else:
impl[^1]
else:
error("This macro only works on variables", val)
이제 테스트해 봅시다. 우리는 이미 잘 했습니다.var a = 100
a *= 3
assert a == 300
resetToDecl(a)
assert a == 100
var b: int
b = 300
assert b == 300
b *= 3
assert b == 900
b.resetToDecl
assert b == 0
예를 들어 보려면 다음과 같은 복잡한 패키지가 많습니다.Slicerator
Oopsie
Constructor
Nimscripter
Nettyrpc
Kashae
Reference
이 문제에 관하여(Nim 중홍의 수수께끼 풀기.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/beef331/demystification-of-macros-in-nim-13n8텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)