Added equality
This commit is contained in:
parent
3633ff9ae9
commit
35fef5c605
2 changed files with 50 additions and 3 deletions
|
|
@ -115,7 +115,7 @@ A couple of limitations fo the `adt` macro:
|
||||||
* field names must be unique across branches (that is, different variants cannot have two fields with the same name). This is actually a limitation of Nim.
|
* field names must be unique across branches (that is, different variants cannot have two fields with the same name). This is actually a limitation of Nim.
|
||||||
* the shortcut that groups field names by type does not seem to work, that is, in the above example one could not write `Rectangle(w, h: float)`.
|
* the shortcut that groups field names by type does not seem to work, that is, in the above example one could not write `Rectangle(w, h: float)`.
|
||||||
|
|
||||||
In the future, Patty will also add a proper definition of equality and copy constructors. Also, some work needs to be done to make it easier to use the generated contructors with `ref` types, in particular for the important case of recursive algebraic data types.
|
In the future, Patty may also add copy constructors. Also, some work needs to be done to make it easier to use the generated contructors with `ref` types, in particular for the important case of recursive algebraic data types.
|
||||||
|
|
||||||
Things that do not work (yet)
|
Things that do not work (yet)
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
|
||||||
51
patty.nim
51
patty.nim
|
|
@ -1,4 +1,4 @@
|
||||||
import macros
|
import macros, sequtils
|
||||||
|
|
||||||
const enumSuffix = "E"
|
const enumSuffix = "E"
|
||||||
|
|
||||||
|
|
@ -109,14 +109,61 @@ proc defineConstructor(e, n: NimNode): NimNode {. compileTime .} =
|
||||||
else:
|
else:
|
||||||
error("Invalid ADT case: " & $(toStrLit(n)))
|
error("Invalid ADT case: " & $(toStrLit(n)))
|
||||||
|
|
||||||
|
proc eqFor(n: NimNode): NimNode {. compileTime .} =
|
||||||
|
if n.kind == nnkObjConstr:
|
||||||
|
result = newNimNode(nnkOfBranch).add(n[0] & enumSuffix)
|
||||||
|
var comparisons: seq[NimNode] = @[]
|
||||||
|
|
||||||
|
for c in tail(n):
|
||||||
|
comparisons.add(infix(newDotExpr(ident("a"), c[0]), "==", newDotExpr(ident("b"), c[0])))
|
||||||
|
|
||||||
|
let body = foldr(comparisons, infix(a, "and", b))
|
||||||
|
|
||||||
|
result.add(newStmtList(newNimNode(nnkReturnStmt).add(body)))
|
||||||
|
elif n.kind == nnkIdent:
|
||||||
|
result = newNimNode(nnkOfBranch).add(n & enumSuffix)
|
||||||
|
result.add(newStmtList(newNimNode(nnkReturnStmt).add(ident("true"))))
|
||||||
|
else:
|
||||||
|
error("Invalid ADT case: " & $(toStrLit(n)))
|
||||||
|
|
||||||
|
|
||||||
|
proc defineEquality(tp, body: NimNode): NimNode {. compileTime .} =
|
||||||
|
# template compare(content, tp: NimNode) =
|
||||||
|
# proc `==`(a, b: tp): bool =
|
||||||
|
# if a.kind == b.kind: content
|
||||||
|
# else: false
|
||||||
|
var condition = newNimNode(nnkCaseStmt).add(newDotExpr(ident("a"), ident("kind")))
|
||||||
|
for child in children(body):
|
||||||
|
condition.add(eqFor(child))
|
||||||
|
|
||||||
|
var body = newNimNode(nnkIfExpr).add(
|
||||||
|
newNimNode(nnkElifBranch).add(
|
||||||
|
infix(newDotExpr(ident("a"), ident("kind")), "==", newDotExpr(ident("b"), ident("kind"))),
|
||||||
|
condition
|
||||||
|
),
|
||||||
|
newNimNode(nnkElse).add(newStmtList(newNimNode(nnkReturnStmt).add(ident("false"))))
|
||||||
|
)
|
||||||
|
|
||||||
|
result = newProc(
|
||||||
|
name = ident("`==`"),
|
||||||
|
params = [ident("bool"), newIdentDefs(ident("a"), tp), newIdentDefs(ident("b"), tp)],
|
||||||
|
body = body
|
||||||
|
)
|
||||||
|
# result = getAst(compare(condition, tp))
|
||||||
|
|
||||||
macro adt*(e: expr, body: stmt): stmt {. immediate .} =
|
macro adt*(e: expr, body: stmt): stmt {. immediate .} =
|
||||||
result = newStmtList(defineTypes(e, body))
|
result = newStmtList(defineTypes(e, body), defineEquality(e, body))
|
||||||
|
|
||||||
for child in children(body):
|
for child in children(body):
|
||||||
result.add(defineConstructor(e, child))
|
result.add(defineConstructor(e, child))
|
||||||
when defined(pattydebug):
|
when defined(pattydebug):
|
||||||
echo toStrLit(result)
|
echo toStrLit(result)
|
||||||
|
|
||||||
|
adt Shape:
|
||||||
|
Circle(r: float, x: float, y: float)
|
||||||
|
Rectangle(w: float, h: float)
|
||||||
|
Square(side: int)
|
||||||
|
|
||||||
macro match*(e: expr, body: stmt): stmt {. immediate .} =
|
macro match*(e: expr, body: stmt): stmt {. immediate .} =
|
||||||
# A fresh symbol used to hold the evaluation of e
|
# A fresh symbol used to hold the evaluation of e
|
||||||
let sym = genSym()
|
let sym = genSym()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue