Added equality

This commit is contained in:
Andrea Ferretti 2015-07-03 21:04:28 +02:00
commit 35fef5c605
2 changed files with 50 additions and 3 deletions

View file

@ -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.
* 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)
-----------------------------

View file

@ -1,4 +1,4 @@
import macros
import macros, sequtils
const enumSuffix = "E"
@ -109,14 +109,61 @@ proc defineConstructor(e, n: NimNode): NimNode {. compileTime .} =
else:
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 .} =
result = newStmtList(defineTypes(e, body))
result = newStmtList(defineTypes(e, body), defineEquality(e, body))
for child in children(body):
result.add(defineConstructor(e, child))
when defined(pattydebug):
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 .} =
# A fresh symbol used to hold the evaluation of e
let sym = genSym()